New stuff, finalizing things, fixing bugs
This commit is contained in:
parent
066ba2fedb
commit
66fcd5c583
96
README.md
96
README.md
|
@ -1,18 +1,49 @@
|
|||
# Suckless Utilities version 6.3
|
||||
# Suckless Utilities version 6.4
|
||||
## About
|
||||
These are my builds of suckless software such as dwm and st.
|
||||
It's simple to compile these things.
|
||||
These are my builds of suckless software such as dwm and st, based on the work for flexipatch by bakkeby. This aims for much more streamlined configuration and patching than 6.3 (which becomes more complicated over time and whenever more patches are integrated).
|
||||
|
||||
This was designed to save me some sanity in maintaining it as well as easily integrating requested patches, whenever it drops from the flexipatch upstream. This should be easy to hack and build, and should be as fast as the previous versions of my build.
|
||||
|
||||
## Included software
|
||||
|
||||
- dwm
|
||||
- dmenu
|
||||
- st
|
||||
- slstatus
|
||||
- tabbed
|
||||
- sfm
|
||||
- spmenu
|
||||
- dwmblocks-async
|
||||
- slock
|
||||
|
||||
## Notes
|
||||
|
||||
Additionals are spmenu configs made by myself, as well as scripts for `spmenu_run`. If you prefer dmenu, it still exists, and could be launched via `Win/Super/Cmd+Alt+S`, while `Win/Super/Cmd+S` would launch `spmenu_run -d` by default (only with .desktop entries, while `Win/Super/Cmd+Shift+S` would launch `spmenu_run` in a similar fashion to dmenu.
|
||||
### Compatibility notes
|
||||
|
||||
For those who want the old version, check out `oldmain`. I don't plan on maintaining it myself since the flexipatch base means much more flexibility over codebase updates as well as new patches.
|
||||
|
||||
Note that there are some programs that is included here, mainly for compatibility or choice reasons. While slstatus is pretty barebones compared to dwmblocks-async, it is included on the repo if one decides not to have statuscmd, for example. This aims to be also compatible with already existing setups.
|
||||
|
||||
### Keybind notes
|
||||
|
||||
In the documentation for this suite, <kbd>Mod4Key</kbd> would be defined as <kbd>⊞ Win</kbd>/<kbd>⌘ Cmd</kbd>/<kbd>❖ Super</kbd>, depending on whichever keyboard do you use.
|
||||
|
||||
In most cases, you probably have only <kbd>⊞ Win</kbd>, but I added <kbd>⌘ Cmd</kbd> and <kbd>❖ Super</kbd> for Mac and advanced Linux/Unix users, respectively.
|
||||
|
||||
If one uses ChromeOS, <kbd>⊞ Win</kbd> equals to the <kbd>🔍 Search</kbd> key. But I don't know who uses X11 window managers inside ChromeOS.
|
||||
|
||||
For new to dwm, <kbd>MODKEY</kbd> or <kbd>Mod1Mask</kbd> is the <kbd>Alt</kbd> key.
|
||||
|
||||
### spmenu notes
|
||||
|
||||
Additionals are spmenu configs made by myself, as well as scripts for `spmenu_run`. If you prefer dmenu, it still exists, and could be launched via <kbd>⊞ Win</kbd>/<kbd>⌘ Cmd</kbd>/<kbd>❖ Super</kbd>+<kbd>Alt</kbd>+<kbd>S</kbd>, while <kbd>⊞ Win</kbd>/<kbd>⌘ Cmd</kbd>/<kbd>❖ Super</kbd>+<kbd>S</kbd> would launch `spmenu_run -d` by default (only with .desktop entries, while <kbd>⊞ Win</kbd>/<kbd>⌘ Cmd</kbd>/<kbd>❖ Super</kbd>+<kbd>Shift</kbd>+<kbd>S</kbd> would launch `spmenu_run` in a similar fashion to dmenu.
|
||||
|
||||
Some user scripts are also included, which has it's own set of dependencies. For example, `clipmenu-spmenu` needs `xsel` and `clipnotify`. These are optional, however.
|
||||
|
||||
```
|
||||
clipmenu-spmenu dependencies:
|
||||
- xsel
|
||||
- clipnotify (included on the folder)
|
||||
- clipnotify
|
||||
|
||||
screenshot-spmenu dependencies:
|
||||
- curl
|
||||
|
@ -25,19 +56,23 @@ screenshot-spmenu dependencies:
|
|||
wallpaper-spmenu dependencies:
|
||||
- xwallpaper
|
||||
```
|
||||
## Building
|
||||
|
||||
1. Install necessary tools and libraries
|
||||
Additionally, spmenu will not work on macOS, so use `dmenu` instead.
|
||||
|
||||
## Building
|
||||
### Prerequisites
|
||||
```
|
||||
Linux/Unix users:
|
||||
- xorg (including drivers of course)
|
||||
- base-devel (or build-essential/s)
|
||||
- libX11(-devel or -dev)
|
||||
- libXft(-devel or -dev)
|
||||
- libXcb(-devel or -dev)
|
||||
- libXrender(-devel or -dev)
|
||||
- libXinerama(-devel or -dev)
|
||||
- freetype(-devel or -dev)
|
||||
- fontconfig(-devel or -dev)
|
||||
- Nerd Fonts (for slstatus)
|
||||
- Nerd Fonts (Hack as default, can be changed manually)
|
||||
- imlibs2(-devel or -dev)
|
||||
- picom (for transparency)
|
||||
- feh (optional)
|
||||
|
@ -64,11 +99,15 @@ For spmenu:
|
|||
- libconfig(-devel or -dev)
|
||||
- OpenSSL or libssl(-devel or -dev)
|
||||
- meson
|
||||
|
||||
Refer to patches.def.h and config.mk for additional patch-related requirements.
|
||||
```
|
||||
|
||||
### Compiling the whole thing
|
||||
1. Install necessary tools and libraries
|
||||
2. Clone this repository (`git clone --recurse-submodules`)
|
||||
3. Change directory to what suckless software do you want to use
|
||||
4. Remove the `config.h` file, to make sure all patches are applied correctly
|
||||
4. Remove the `config.h`, and `patches.h` files, to make sure all patches are applied correctly
|
||||
5. Copy `make clean install` and paste it on your terminal
|
||||
6. Building the spmenu submodule included in this repo (by speedie) would strictly use meson as it's build system.
|
||||
1. For that, `cd` to the spmenu folder.
|
||||
|
@ -76,42 +115,49 @@ For spmenu:
|
|||
3. Run `ninja -C build` for building the binaries.
|
||||
4. Install via `meson install -C build`, and it'll prompt you if you would like to use sudo if not run as root.
|
||||
|
||||
7. Insert dwm, slstatus and/or st inside your `.xinitrc` using your favorite text editor (usually located in `/home/<username>/.xinitrc`)
|
||||
8. Start it and done!
|
||||
7. Insert dwm, slstatus and/or st inside your `.xinitrc` using your favorite text editor (usually located in `$HOME/.xinitrc`)
|
||||
- Additionally, a script called `startdwm` located in `desktop` could be installed in `/usr/local/bin` which could be used to launch dwm on display managers, such as GDM or SDDM.
|
||||
- `startdwm` could be also used as the xinitrc script by putting it under $HOME and renaming it to `.xinitrc`.
|
||||
8. Install the `dwmblocks` scripts (in `scripts/dwmblocks`) to your `$PATH`.
|
||||
9. Start it and done!
|
||||
|
||||
## Current bugs
|
||||
- ~~Taskbar not working properly~~ (fixed in commit [e9015f2](https://github.com/Lucas-mother3/suckless-utils/commit/e9015f2d2a09ef66f1c9e188b277c89d23635195) & [7085f9](https://github.com/Lucas-mother3/suckless-utils/commit/7085f97d80fc203d6f54d0209af07007c0347880)). Thanks, [Speedie](https://speedie.gq)!
|
||||
- ~~Unhiding a hidden window (using the show/hide function) and if it's the only program running, crashes dwm~~
|
||||
- ~~Alt-tab crashes dwm altogther (idk man)~~
|
||||
|
||||
## Future plans
|
||||
- [ ] Rebase the dwm build to dwm-flexipatch (maybe under a new branch with a VM debug environment?)
|
||||
- [ ] Integrate barmodules if the dwm-flexipatch rewrite did happen
|
||||
- [ ] Version jump from 6.3 -> 6.4
|
||||
- [x] Rebase the dwm build to dwm-flexipatch (maybe under a new branch with a VM debug environment?)
|
||||
- [x] Integrate barmodules if the dwm-flexipatch rewrite did happen
|
||||
- [x] Version jump from 6.3 -> 6.4
|
||||
- [ ] Potentially making this project into a desktop environment, when I feel it's ready to do so
|
||||
- [ ] Use `spmenu-desktop-launcher` if it's mature/usable, retaining `spmenu_run` for backwards compatibility with existing scripts
|
||||
- [ ] Making a wiki for documenting functions in this build, as well as other important information about the project
|
||||
|
||||
## Patching even further
|
||||
|
||||
Patching everything is as easy as downloading the diff file, use the `patch` command and apply changes.
|
||||
Patching everything is as easy as editing the `patches.def.h` file included in the repo. Unlike 6.3, which had a complicated codebase, 6.4 aims for a much more streamlined process of patching things, unlike the previous version which would mean using `patch` and manually editing files whenever something isn't patched up properly.
|
||||
|
||||
But, since this is a heavily patched version of everything, I wouldn't recommend patching even further unless if you know what you're doing.
|
||||
A huge thanks for bakkeby on the work for making suckless software easier to patch, meaning more people could modify and configure the code to their liking.
|
||||
|
||||
## Contributing to the project
|
||||
|
||||
Contributions are welcome, as long as it follows the defined rules in [the CONTRIBUTING document](/CONTRIBUTING.md).
|
||||
|
||||
Documentations are also welcome, in fact, I do need someone who could maintain documentation for the project's inner workings.
|
||||
|
||||
## How the versioning system works
|
||||
|
||||
Suckless Uilities (the whole package and not the individual components) are versioned under the current version of the repo's dwm.
|
||||
Even if dwm 6.4 releases, if the repo still uses dwm 6.3 for compatibility reasons, the whole package will be still be Suckless Utilities 6.3.
|
||||
Suckless Utilities (the whole package and not the individual components) are versioned under the current version of the repo's dwm.
|
||||
Even if dwm(-flexipatch) 6.5 releases, if the repo still uses dwm(-flexipatch) 6.4 for compatibility reasons, the whole package will still be Suckless Utilities 6.4.
|
||||
|
||||
## Licensing
|
||||
All programs are licensed under the MIT License, which sucks, and worse than GNU GPL, but hey, it's better than proprietary code!
|
||||
All programs are licensed under the MIT License, except for some submodules, which might have different licenses (for example, GPLv2).
|
||||
|
||||
## Screenshots
|
||||
![Screenshot of neofetch](/pics/neofetch.png)
|
||||
![Screenshot of random applications (Spotify, Space Cadet Pinball, NCSA Mosaic)](/pics/random.png)
|
||||
![Screenshot of random applications](/pics/random.png)
|
||||
|
||||
## Special thanks
|
||||
* [Speedie](https://speedie.gq) for helping me out with this and providing me with patches
|
||||
* [Speedie](https://speedie.site) for helping me out with this and providing me with patches
|
||||
* [The suckless team](https://suckless.org) for maintaining suckless software suck less
|
||||
* [bakkeby](https://github.com/bakkeby) for creating dwm-flexipatch and related projects, making it possible to easily integrate patches
|
||||
|
||||
## Mirrors
|
||||
|
||||
|
|
8
desktop/startdwm
Executable file
8
desktop/startdwm
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
systemctl --user restart clipmenud.service # restarts clipmenud, if installed
|
||||
wal -i "/usr/local/share/wallpapers/opensuse.png" --backend colorz # could be changed
|
||||
picom -b # launches compositor
|
||||
/usr/local/bin/dwmblocks & # launches slstatus/dwmblocks
|
||||
/usr/bin/dunst & # launches dunst daemon
|
||||
paplay /usr/share/sounds/Oxygen-Sys-Special.ogg # autoplay sound, optional
|
||||
exec /usr/local/bin/dwm # launch dwm
|
|
@ -1,4 +1,5 @@
|
|||
*.o
|
||||
config.h
|
||||
patches.h
|
||||
dmenu
|
||||
stest
|
||||
config.h
|
|
@ -20,7 +20,10 @@ options:
|
|||
config.h:
|
||||
cp config.def.h $@
|
||||
|
||||
$(OBJ): arg.h config.h config.mk drw.h
|
||||
patches.h:
|
||||
cp patches.def.h $@
|
||||
|
||||
$(OBJ): arg.h config.h config.mk drw.h patches.h
|
||||
|
||||
dmenu: dmenu.o drw.o util.o
|
||||
$(CC) -o $@ dmenu.o drw.o util.o $(LDFLAGS)
|
265
dmenu-flexipatch/README.md
Normal file
265
dmenu-flexipatch/README.md
Normal file
|
@ -0,0 +1,265 @@
|
|||
Similar to [dwm-flexipatch](https://github.com/bakkeby/dwm-flexipatch) this dmenu 5.2 (0fe460d,
|
||||
2023-04-05) project has a different take on patching. It uses preprocessor directives to decide
|
||||
whether or not to include a patch during build time. Essentially this means that this build, for
|
||||
better or worse, contains both the patched _and_ the original code. The aim being that you can
|
||||
select which patches to include and the build will contain that code and nothing more.
|
||||
|
||||
For example to include the `alpha` patch then you would only need to flip this setting from 0
|
||||
to 1 in [patches.h](https://github.com/bakkeby/dmenu-flexipatch/blob/master/patches.def.h):
|
||||
```c
|
||||
#define ALPHA_PATCH 1
|
||||
```
|
||||
|
||||
Once you have found out what works for you and what doesn't then you should be in a better position
|
||||
to choose patches should you want to start patching from scratch.
|
||||
|
||||
Alternatively if you have found the patches you want, but don't want the rest of the flexipatch
|
||||
entanglement on your plate then you may want to have a look at
|
||||
[flexipatch-finalizer](https://github.com/bakkeby/flexipatch-finalizer); a custom pre-processor
|
||||
tool that removes all the unused flexipatch code leaving you with a build that contains the patches
|
||||
you selected.
|
||||
|
||||
Refer to [https://tools.suckless.org/dmenu/](https://tools.suckless.org/dmenu/) for details on
|
||||
dmenu, how to install it and how it works.
|
||||
|
||||
Browsing patches? There is a [map of patches](https://coggle.it/diagram/YjT2DD6jBM9dayf3) diagram which tries to organise patches into categories.
|
||||
|
||||
---
|
||||
|
||||
### Changelog:
|
||||
|
||||
2023-06-15 - Added the caret width patch
|
||||
|
||||
2022-09-05 - Removed the json patch due to maintenance and compatibility reasons, added the
|
||||
separator patch
|
||||
|
||||
2022-09-04 - Added the fzfexpect patch
|
||||
|
||||
2022-06-21 - Adding barpadding patch and relative input width patch
|
||||
|
||||
2022-03-02 - Bump to 5.1
|
||||
|
||||
2021-05-23 - Adding support for `ctrl+v` to paste and adding emoji-highlight patch
|
||||
|
||||
2021-05-17 - Added the restrict return, no sort, gridnav and plain-prompt (listfullwidth) patches
|
||||
|
||||
2021-05-15 - Added the tsv and printindex patches
|
||||
|
||||
2020-08-08 - Added the json, symbols, managed, morecolor, multi-selection and preselect patches
|
||||
|
||||
2020-08-05 - Added the grid, highlight, highpriority, dynamic options and numbers patches
|
||||
|
||||
2020-06-13 - Added the pango patch
|
||||
|
||||
2020-06-10 - Added the case-insensitive patch
|
||||
|
||||
2020-05-29 - Added the alpha patch (derived from Baitinq's [build](https://github.com/Baitinq/dmenu))
|
||||
and the color emoji patch
|
||||
|
||||
2020-04-05 - Added fuzzyhighlight patch
|
||||
|
||||
2020-02-09 - Added revised border patch (adding command line parameter for setting border width)
|
||||
|
||||
2019-12-29 - Added xresources patch
|
||||
|
||||
2019-10-16 - Introduced [flexipatch-finalizer](https://github.com/bakkeby/flexipatch-finalizer)
|
||||
|
||||
2019-09-18 - Added border, center, fuzzymatch, incremental, initialtext, instant, line-height,
|
||||
mouse-support, navhistory, non-blocking-stdin, password, pipeout, printinputtext,
|
||||
rejectnomatch, scroll, vertfull, wmtype and xyw patches
|
||||
|
||||
### Patches included:
|
||||
|
||||
- [alpha](https://github.com/bakkeby/patches/blob/master/dmenu/dmenu-alpha-5.0_20210725_523aa08.diff)
|
||||
- adds transparency for the dmenu window
|
||||
|
||||
- [barpadding](https://github.com/bakkeby/patches/wiki/barpadding)
|
||||
- adds padding for dmenu in similar fashion to the [barpadding](https://dwm.suckless.org/patches/barpadding/)
|
||||
patch for dwm
|
||||
|
||||
- [border](http://tools.suckless.org/dmenu/patches/border/)
|
||||
- adds a border around the dmenu window
|
||||
|
||||
- [caret-width](https://github.com/DarkSamus669/dmenu-patches/blob/main/dmenu-caretwidth-5.2.diff)
|
||||
- makes the caret width configurable and overridable via a command line option
|
||||
|
||||
- [case-insensitive](http://tools.suckless.org/dmenu/patches/case-insensitive/)
|
||||
- makes dmenu case-insensitive by default, replacing the case-insensitive `-i` option with a
|
||||
case sensitive `-s` option
|
||||
|
||||
- [center](https://tools.suckless.org/dmenu/patches/center/)
|
||||
- this patch centers dmenu in the middle of the screen
|
||||
|
||||
- color_emoji
|
||||
- enables color emoji in dmenu by removing a workaround for a BadLength error in the Xft
|
||||
library when color glyphs are used
|
||||
- enabling this will crash dmenu on encountering such glyphs unless you also have an updated
|
||||
Xft library that can handle them
|
||||
|
||||
- [dynamic_options](https://tools.suckless.org/dmenu/patches/dynamicoptions/)
|
||||
- adds a flag (`-dy`) which makes dmenu run the command given to it whenever input is changed
|
||||
with the current input as the last argument and update the option list according to the
|
||||
output of that command
|
||||
|
||||
- [emoji-highlight](https://tools.suckless.org/dmenu/patches/emoji-highlight/)
|
||||
- this patch will allow for emojis on the left side with a colored background when selected
|
||||
|
||||
- [fuzzyhighlight](https://tools.suckless.org/dmenu/patches/fuzzyhighlight/)
|
||||
- intended to be combined with the fuzzymatch patch, this makes it so that fuzzy matches are
|
||||
highlighted
|
||||
|
||||
- [fuzzymatch](https://tools.suckless.org/dmenu/patches/fuzzymatch/)
|
||||
- adds support for fuzzy-matching to dmenu, allowing users to type non-consecutive portions
|
||||
of the string to be matched
|
||||
|
||||
- [fzfexpect](https://github.com/DAFF0D11/dafmenu/blob/master/patches/dmenu-fzfexpect-5.1.diff)
|
||||
- adds fzf expect functionality in dmenu
|
||||
|
||||
- [grid](https://tools.suckless.org/dmenu/patches/grid/)
|
||||
- allows dmenu's entries to be rendered in a grid by adding a new `-g` flag to specify the
|
||||
number of grid columns
|
||||
- the `-g` and `-l` options can be used together to create a G columns * L lines grid
|
||||
|
||||
- [gridnav](https://tools.suckless.org/dmenu/patches/gridnav/)
|
||||
- adds the ability to move left and right through a grid (when using the grid patch)
|
||||
|
||||
- [highlight](https://tools.suckless.org/dmenu/patches/highlight/)
|
||||
- this patch highlights the individual characters of matched text for each dmenu list entry
|
||||
|
||||
- [highpriority](https://tools.suckless.org/dmenu/patches/highpriority/)
|
||||
- this patch will automatically sort the search result so that high priority items are shown
|
||||
first
|
||||
|
||||
- [incremental](https://tools.suckless.org/dmenu/patches/incremental/)
|
||||
- this patch causes dmenu to print out the current text each time a key is pressed
|
||||
|
||||
- [initialtext](https://tools.suckless.org/dmenu/patches/initialtext/)
|
||||
- adds an option to provide preselected text
|
||||
|
||||
- [instant](https://tools.suckless.org/dmenu/patches/instant/)
|
||||
- adds a flag that will cause dmenu to select an item immediately if there is only one
|
||||
matching option left
|
||||
|
||||
- [~json~](https://tools.suckless.org/dmenu/patches/json/)
|
||||
- ~adds basic support for json files~
|
||||
|
||||
- [line-height](http://tools.suckless.org/dmenu/patches/line-height/)
|
||||
- adds a `-h` option which sets the minimum height of a dmenu line
|
||||
- this helps integrate dmenu with other UI elements that require a particular vertical size
|
||||
|
||||
- [managed](https://tools.suckless.org/dmenu/patches/managed/)
|
||||
- adds a `-wm` flag which sets override_redirect to false; thus letting your window manager
|
||||
manage the dmenu window
|
||||
- this may be helpful in contexts where you don't want to exclusively bind dmenu or want to
|
||||
treat dmenu more as a "window" rather than as an overlay
|
||||
|
||||
- [morecolor](https://tools.suckless.org/dmenu/patches/morecolor/)
|
||||
- adds an additional color scheme for highlighting entries adjacent to the current selection
|
||||
|
||||
- [mouse-support](https://tools.suckless.org/dmenu/patches/mouse-support/)
|
||||
- adds basic mouse support for dmenu
|
||||
|
||||
- [multi-selection](https://tools.suckless.org/dmenu/patches/multi-selection/)
|
||||
- without this patch when you press `Ctrl+Enter` dmenu just outputs current item and it is
|
||||
not possible to undo that
|
||||
- with this patch dmenu will output all selected items only on exit
|
||||
- it is also possible to deselect any selected item
|
||||
|
||||
- [navhistory](https://tools.suckless.org/dmenu/patches/navhistory/)
|
||||
- provides dmenu the ability for history navigation similar to that of bash
|
||||
|
||||
- [no-sort](https://tools.suckless.org/dmenu/patches/no-sort/)
|
||||
- adds the `-S` option to disable sorting menu items after matching
|
||||
- useful, for example, when menu items are sorted by their frequency of use (using an
|
||||
external cache) and the most frequently selected items should always appear first regardless
|
||||
of how they were exact, prefix, or substring matches
|
||||
|
||||
- [non-blocking-stdin](https://tools.suckless.org/dmenu/patches/non_blocking_stdin/)
|
||||
- this is a patch to have dmenu read stdin in a non blocking way, making it wait for input
|
||||
both from stdin and from X
|
||||
- this means that you can continue feeding dmenu while you type
|
||||
- the patch is meant to be used along with the incremental patch in order to use stdout to
|
||||
feed stdin
|
||||
|
||||
- [numbers](https://tools.suckless.org/dmenu/patches/numbers/)
|
||||
- adds text which displays the number of matched and total items in the top right corner of
|
||||
dmenu
|
||||
|
||||
- [pango](https://github.com/StillANixRookie/dmenu-pango/)
|
||||
- adds simple markup for dmenu using pango markup
|
||||
|
||||
- [password](https://tools.suckless.org/dmenu/patches/password/)
|
||||
- with this patch dmenu will not directly display the keyboard input, but instead replace it
|
||||
with dots
|
||||
- all data from stdin will be ignored
|
||||
|
||||
- [pipeout](https://tools.suckless.org/dmenu/patches/pipeout/)
|
||||
- this patch allows the selected text to be piped back out with dmenu
|
||||
- this can be useful if you want to display the output of a command on the screen
|
||||
|
||||
- [plain-prompt](https://tools.suckless.org/dmenu/patches/listfullwidth/)
|
||||
- simple change that avoids colors for the prompt by making it use the same style as the
|
||||
rest of the input field
|
||||
|
||||
- [prefix-completion](https://tools.suckless.org/dmenu/patches/prefix-completion/)
|
||||
- changes the behaviour of matched items and the Tab key to allow tab completion
|
||||
|
||||
- [preselect](https://tools.suckless.org/dmenu/patches/preselect/)
|
||||
- adds an option `-ps` to preselect an item by providing the index that should be pre-selected
|
||||
|
||||
- [printindex](https://tools.suckless.org/dmenu/patches/printindex/)
|
||||
- allows dmenu to print out the 0-based index of matched text instead of the matched text
|
||||
itself
|
||||
- this can be useful in cases where you would like to select entries from one array of text
|
||||
but index into another, or when you are selecting from an ordered list of non-unique items
|
||||
|
||||
- [printinputtext](https://tools.suckless.org/dmenu/patches/printinputtext/)
|
||||
- this patch adds a flag `-t` which makes Return key ignore selection and print the input
|
||||
text to stdout
|
||||
- the flag basically swaps the functions of Return and Shift+Return hotkeys
|
||||
|
||||
- [rejectnomatch](https://tools.suckless.org/dmenu/patches/reject-no-match/)
|
||||
- adds a new flag to dmenu with which text input will be rejected if it would result in no
|
||||
matching item
|
||||
|
||||
- relative_input_width
|
||||
- prior to commit [e1e1de7](https://git.suckless.org/dmenu/commit/e1e1de7b3b8399cba90ddca9613f837b2dbef7b9.html)
|
||||
the input width was calculated based on the input options
|
||||
- this feature was removed in favour of hardcoding the input width to always take up 1/3rd of
|
||||
the available space
|
||||
- this patch adds that feature back in with some bespoke performance optimisations at the cost
|
||||
of accuracy and correctness
|
||||
|
||||
- [restrict-return](https://tools.suckless.org/dmenu/patches/restrict-return/)
|
||||
- adds a `-1` option which disables Shift-Return and Ctrl-Return
|
||||
- this guarantees that dmenu will only output one item, and that item was read from stdin
|
||||
|
||||
- [scroll](https://tools.suckless.org/dmenu/patches/scroll/)
|
||||
- this patch adds support for text scrolling
|
||||
- it doesn't append `...` for long input anymore as it can handle long text
|
||||
|
||||
- [separator](https://tools.suckless.org/dmenu/patches/separator/)
|
||||
- adds `-d` and `-D` flags which separates the input into two halves; one half to be
|
||||
displayed in dmenu and the other to be printed to stdout
|
||||
|
||||
- [symbols](https://tools.suckless.org/dmenu/patches/symbols/)
|
||||
- allows the symbols, which are printed in dmenu to indicate that either the input is too
|
||||
long or there are too many options to be shown in dmenu in one line, to be defined
|
||||
|
||||
- [tsv](https://tools.suckless.org/dmenu/patches/tsv/)
|
||||
- makes dmenu split input lines at first tab character and only display first part, but it
|
||||
will perform matching on and output full lines as usual
|
||||
- can be useful if you want to separate data and representation
|
||||
|
||||
- [vertfull](https://tools.suckless.org/dmenu/patches/vertfull/)
|
||||
- prevents dmenu from indenting items at the same level as the prompt length
|
||||
|
||||
- [wmtype](https://github.com/Baitinq/dmenu/blob/master/patches/dmenu-wm_type.diff)
|
||||
- adds extended window manager hints such as \_NET_WM_WINDOW_TYPE and \_NET_WM_WINDOW_TYPE_DOCK
|
||||
|
||||
- [xresources](https://tools.suckless.org/dmenu/patches/xresources/)
|
||||
- allows dmenu to read font and colors from Xresources
|
||||
- note that with this patch the Xresources settings takes precedence over command line arguments
|
||||
|
||||
- [xyw](https://tools.suckless.org/dmenu/patches/xyw/)
|
||||
- adds options for specifying dmenu window position and width
|
153
dmenu-flexipatch/config.def.h
Normal file
153
dmenu-flexipatch/config.def.h
Normal file
|
@ -0,0 +1,153 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
/* Default settings; can be overriden by command line. */
|
||||
|
||||
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
|
||||
#if ALPHA_PATCH
|
||||
static int opacity = 1; /* -o option; if 0, then alpha is disabled */
|
||||
#endif // ALPHA_PATCH
|
||||
#if CARET_WIDTH_PATCH
|
||||
static int caret_width = 2; /* -cw option; set default caret width */
|
||||
#endif // CARET_WIDTH_PATCH
|
||||
#if FUZZYMATCH_PATCH
|
||||
static int fuzzy = 1; /* -F option; if 0, dmenu doesn't use fuzzy matching */
|
||||
#endif // FUZZYMATCH_PATCH
|
||||
#if INCREMENTAL_PATCH
|
||||
static int incremental = 0; /* -r option; if 1, outputs text each time a key is pressed */
|
||||
#endif // INCREMENTAL_PATCH
|
||||
#if INSTANT_PATCH
|
||||
static int instant = 0; /* -n option; if 1, selects matching item without the need to press enter */
|
||||
#endif // INSTANT_PATCH
|
||||
#if CENTER_PATCH
|
||||
static int center = 1; /* -c option; if 0, dmenu won't be centered on the screen */
|
||||
static int min_width = 500; /* minimum width when centered */
|
||||
#endif // CENTER_PATCH
|
||||
#if BARPADDING_PATCH
|
||||
static const int vertpad = 10; /* vertical padding of bar */
|
||||
static const int sidepad = 10; /* horizontal padding of bar */
|
||||
#endif // BARPADDING_PATCH
|
||||
#if RESTRICT_RETURN_PATCH
|
||||
static int restrict_return = 0; /* -1 option; if 1, disables shift-return and ctrl-return */
|
||||
#endif // RESTRICT_RETURN_PATCH
|
||||
/* -fn option overrides fonts[0]; default X11 font or font set */
|
||||
#if PANGO_PATCH
|
||||
static char font[] = "Hack Nerd Font 12";
|
||||
#else
|
||||
#if XRESOURCES_PATCH
|
||||
static char *fonts[] =
|
||||
#else
|
||||
static const char *fonts[] =
|
||||
#endif // XRESOURCES_PATCH
|
||||
{
|
||||
"Hack Nerd Font:size=12"
|
||||
};
|
||||
#endif // PANGO_PATCH
|
||||
#if MANAGED_PATCH
|
||||
static char *prompt = NULL; /* -p option; prompt to the left of input field */
|
||||
#else
|
||||
static const char *prompt = NULL; /* -p option; prompt to the left of input field */
|
||||
#endif // MANAGED_PATCH
|
||||
#if DYNAMIC_OPTIONS_PATCH
|
||||
static const char *dynamic = NULL; /* -dy option; dynamic command to run on input change */
|
||||
#endif // DYNAMIC_OPTIONS_PATCH
|
||||
#if SYMBOLS_PATCH
|
||||
static const char *symbol_1 = "<";
|
||||
static const char *symbol_2 = ">";
|
||||
#endif // SYMBOLS_PATCH
|
||||
|
||||
#if ALPHA_PATCH
|
||||
static const unsigned int baralpha = 0xd0;
|
||||
static const unsigned int borderalpha = OPAQUE;
|
||||
static const unsigned int alphas[][3] = {
|
||||
/* fg bg border */
|
||||
[SchemeNorm] = { OPAQUE, baralpha, borderalpha },
|
||||
[SchemeSel] = { OPAQUE, baralpha, borderalpha },
|
||||
#if BORDER_PATCH
|
||||
[SchemeBorder] = { OPAQUE, OPAQUE, OPAQUE },
|
||||
#endif // BORDER_PATCH
|
||||
#if MORECOLOR_PATCH
|
||||
[SchemeMid] = { OPAQUE, baralpha, borderalpha },
|
||||
#endif // MORECOLOR_PATCH
|
||||
#if HIGHLIGHT_PATCH || FUZZYHIGHLIGHT_PATCH
|
||||
[SchemeSelHighlight] = { OPAQUE, baralpha, borderalpha },
|
||||
[SchemeNormHighlight] = { OPAQUE, baralpha, borderalpha },
|
||||
#endif // HIGHLIGHT_PATCH | FUZZYHIGHLIGHT_PATCH
|
||||
#if HIGHPRIORITY_PATCH
|
||||
[SchemeHp] = { OPAQUE, baralpha, borderalpha },
|
||||
#endif // HIGHPRIORITY_PATCH
|
||||
#if EMOJI_HIGHLIGHT_PATCH
|
||||
[SchemeHover] = { OPAQUE, baralpha, borderalpha },
|
||||
[SchemeGreen] = { OPAQUE, baralpha, borderalpha },
|
||||
[SchemeRed] = { OPAQUE, baralpha, borderalpha },
|
||||
[SchemeYellow] = { OPAQUE, baralpha, borderalpha },
|
||||
[SchemeBlue] = { OPAQUE, baralpha, borderalpha },
|
||||
[SchemePurple] = { OPAQUE, baralpha, borderalpha },
|
||||
#endif // EMOJI_HIGHLIGHT_PATCH
|
||||
};
|
||||
#endif // ALPHA_PATCH
|
||||
|
||||
static
|
||||
#if !XRESOURCES_PATCH
|
||||
const
|
||||
#endif // XRESOURCES_PATCH
|
||||
char *colors[][2] = {
|
||||
/* fg bg */
|
||||
[SchemeNorm] = { "#bbbbbb", "#222222" },
|
||||
[SchemeSel] = { "#eeeeee", "#005577" },
|
||||
[SchemeOut] = { "#000000", "#00ffff" },
|
||||
#if BORDER_PATCH
|
||||
[SchemeBorder] = { "#000000", "#005577" },
|
||||
#endif // BORDER_PATCH
|
||||
#if MORECOLOR_PATCH
|
||||
[SchemeMid] = { "#eeeeee", "#770000" },
|
||||
#endif // MORECOLOR_PATCH
|
||||
#if HIGHLIGHT_PATCH || FUZZYHIGHLIGHT_PATCH
|
||||
[SchemeSelHighlight] = { "#ffc978", "#005577" },
|
||||
[SchemeNormHighlight] = { "#ffc978", "#222222" },
|
||||
#endif // HIGHLIGHT_PATCH | FUZZYHIGHLIGHT_PATCH
|
||||
#if HIGHPRIORITY_PATCH
|
||||
[SchemeHp] = { "#bbbbbb", "#333333" },
|
||||
#endif // HIGHPRIORITY_PATCH
|
||||
#if EMOJI_HIGHLIGHT_PATCH
|
||||
[SchemeHover] = { "#ffffff", "#353D4B" },
|
||||
[SchemeGreen] = { "#ffffff", "#52E067" },
|
||||
[SchemeRed] = { "#ffffff", "#e05252" },
|
||||
[SchemeYellow] = { "#ffffff", "#e0c452" },
|
||||
[SchemeBlue] = { "#ffffff", "#5280e0" },
|
||||
[SchemePurple] = { "#ffffff", "#9952e0" },
|
||||
#endif // EMOJI_HIGHLIGHT_PATCH
|
||||
};
|
||||
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
|
||||
static unsigned int lines = 0;
|
||||
#if GRID_PATCH
|
||||
/* -g option; if nonzero, dmenu uses a grid comprised of columns and lines */
|
||||
static unsigned int columns = 0;
|
||||
#endif // GRID_PATCH
|
||||
#if LINE_HEIGHT_PATCH
|
||||
static unsigned int lineheight = 0; /* -h option; minimum height of a menu line */
|
||||
static unsigned int min_lineheight = 8;
|
||||
#endif // LINE_HEIGHT_PATCH
|
||||
#if NAVHISTORY_PATCH
|
||||
static unsigned int maxhist = 15;
|
||||
static int histnodup = 1; /* if 0, record repeated histories */
|
||||
#endif // NAVHISTORY_PATCH
|
||||
|
||||
/*
|
||||
* Characters not considered part of a word while deleting words
|
||||
* for example: " /?\"&[]"
|
||||
*/
|
||||
#if PIPEOUT_PATCH
|
||||
static const char startpipe[] = "#";
|
||||
#endif // PIPEOUT_PATCH
|
||||
static const char worddelimiters[] = " ";
|
||||
|
||||
#if BORDER_PATCH
|
||||
/* Size of the window border */
|
||||
static unsigned int border_width = 0;
|
||||
#endif // BORDER_PATCH
|
||||
|
||||
#if PREFIXCOMPLETION_PATCH
|
||||
/*
|
||||
* Use prefix matching by default; can be inverted with the -x flag.
|
||||
*/
|
||||
static int use_prefix = 1;
|
||||
#endif // PREFIXCOMPLETION_PATCH
|
|
@ -1,5 +1,5 @@
|
|||
# dmenu version
|
||||
VERSION = 5.1
|
||||
VERSION = 5.2
|
||||
|
||||
# paths
|
||||
PREFIX = /usr/local
|
||||
|
@ -15,19 +15,26 @@ XINERAMAFLAGS = -DXINERAMA
|
|||
# freetype
|
||||
FREETYPELIBS = -lfontconfig -lXft
|
||||
FREETYPEINC = /usr/include/freetype2
|
||||
|
||||
# alpha
|
||||
XRENDERLIBS = -lXrender
|
||||
|
||||
# OpenBSD (uncomment)
|
||||
#FREETYPEINC = $(X11INC)/freetype2
|
||||
#MANPREFIX = ${PREFIX}/man
|
||||
|
||||
# uncomment on RHEL for strcasecmp
|
||||
#EXTRAFLAGS=-D_GNU_SOURCE
|
||||
|
||||
# Uncomment this for the alpha patch / ALPHA_PATCH
|
||||
XRENDER = -lXrender
|
||||
|
||||
# Uncomment for the pango patch / PANGO_PATCH
|
||||
#PANGOINC = `pkg-config --cflags xft pango pangoxft`
|
||||
#PANGOLIB = `pkg-config --libs xft pango pangoxft`
|
||||
|
||||
# includes and libs
|
||||
INCS = -I$(X11INC) -I$(FREETYPEINC)
|
||||
LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) ${XRENDERLIBS}
|
||||
INCS = -I$(X11INC) -I$(FREETYPEINC) ${PANGOINC}
|
||||
LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lm $(XRENDER) ${PANGOLIB}
|
||||
|
||||
# flags
|
||||
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS)
|
||||
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) $(EXTRAFLAGS)
|
||||
CFLAGS = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS)
|
||||
LDFLAGS = $(LIBS)
|
||||
|
|
@ -4,8 +4,6 @@ dmenu \- dynamic menu
|
|||
.SH SYNOPSIS
|
||||
.B dmenu
|
||||
.RB [ \-bfiv ]
|
||||
.RB [ \-g
|
||||
.IR columns ]
|
||||
.RB [ \-l
|
||||
.IR lines ]
|
||||
.RB [ \-m
|
||||
|
@ -49,11 +47,8 @@ is faster, but will lock up X until stdin reaches end\-of\-file.
|
|||
.B \-i
|
||||
dmenu matches menu items case insensitively.
|
||||
.TP
|
||||
.BI \-g " columns"
|
||||
dmenu lists items in a grid with the given number of columns.
|
||||
.TP
|
||||
.BI \-l " lines"
|
||||
dmenu lists items in a grid with the given number of lines.
|
||||
dmenu lists items vertically, with the given number of lines.
|
||||
.TP
|
||||
.BI \-m " monitor"
|
||||
dmenu is displayed on the monitor number supplied. Monitor numbers are starting
|
2220
dmenu-flexipatch/dmenu.c
Normal file
2220
dmenu-flexipatch/dmenu.c
Normal file
File diff suppressed because it is too large
Load diff
6
dmenu-flexipatch/dmenu_run
Executable file
6
dmenu-flexipatch/dmenu_run
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
export _JAVA_AWT_WM_NONREPARENTING=1
|
||||
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &
|
||||
|
||||
# Uncomment for the NAVHISTORY patch (and remove the exec above)
|
||||
#dmenu_path | dmenu -H "${XDG_CACHE_HOME:-$HOME/.cache/}/dmenu_run.hist" "$@" | ${SHELL:-"/bin/sh"} &
|
|
@ -5,9 +5,11 @@
|
|||
#include <X11/Xlib.h>
|
||||
#include <X11/Xft/Xft.h>
|
||||
|
||||
#include "patches.h"
|
||||
#include "drw.h"
|
||||
#include "util.h"
|
||||
|
||||
#if !PANGO_PATCH
|
||||
#define UTF_INVALID 0xFFFD
|
||||
#define UTF_SIZ 4
|
||||
|
||||
|
@ -59,9 +61,14 @@ utf8decode(const char *c, long *u, size_t clen)
|
|||
|
||||
return len;
|
||||
}
|
||||
#endif // PANGO_PATCH
|
||||
|
||||
Drw *
|
||||
#if ALPHA_PATCH
|
||||
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
|
||||
#else
|
||||
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
|
||||
#endif // ALPHA_PATCH
|
||||
{
|
||||
Drw *drw = ecalloc(1, sizeof(Drw));
|
||||
|
||||
|
@ -70,11 +77,16 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
|
|||
drw->root = root;
|
||||
drw->w = w;
|
||||
drw->h = h;
|
||||
#if ALPHA_PATCH
|
||||
drw->visual = visual;
|
||||
drw->depth = depth;
|
||||
drw->cmap = cmap;
|
||||
drw->drawable = XCreatePixmap(dpy, root, w, h, depth);
|
||||
drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
|
||||
#else
|
||||
drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
|
||||
drw->gc = XCreateGC(dpy, root, 0, NULL);
|
||||
#endif // ALPHA_PATCH
|
||||
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
|
||||
|
||||
return drw;
|
||||
|
@ -90,7 +102,11 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h)
|
|||
drw->h = h;
|
||||
if (drw->drawable)
|
||||
XFreePixmap(drw->dpy, drw->drawable);
|
||||
#if ALPHA_PATCH
|
||||
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth);
|
||||
#else
|
||||
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
|
||||
#endif // ALPHA_PATCH
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -98,10 +114,49 @@ drw_free(Drw *drw)
|
|||
{
|
||||
XFreePixmap(drw->dpy, drw->drawable);
|
||||
XFreeGC(drw->dpy, drw->gc);
|
||||
#if PANGO_PATCH
|
||||
drw_font_free(drw->font);
|
||||
#else
|
||||
drw_fontset_free(drw->fonts);
|
||||
#endif // PANGO_PATCH
|
||||
free(drw);
|
||||
}
|
||||
|
||||
#if PANGO_PATCH
|
||||
/* This function is an implementation detail. Library users should use
|
||||
* drw_font_create instead.
|
||||
*/
|
||||
static Fnt *
|
||||
xfont_create(Drw *drw, const char *fontname)
|
||||
{
|
||||
Fnt *font;
|
||||
PangoFontMap *fontmap;
|
||||
PangoContext *context;
|
||||
PangoFontDescription *desc;
|
||||
PangoFontMetrics *metrics;
|
||||
|
||||
if (!fontname) {
|
||||
die("no font specified.");
|
||||
}
|
||||
|
||||
font = ecalloc(1, sizeof(Fnt));
|
||||
font->dpy = drw->dpy;
|
||||
|
||||
fontmap = pango_xft_get_font_map(drw->dpy, drw->screen);
|
||||
context = pango_font_map_create_context(fontmap);
|
||||
desc = pango_font_description_from_string(fontname);
|
||||
font->layout = pango_layout_new(context);
|
||||
pango_layout_set_font_description(font->layout, desc);
|
||||
|
||||
metrics = pango_context_get_metrics(context, desc, pango_language_from_string ("en-us"));
|
||||
font->h = pango_font_metrics_get_height(metrics) / PANGO_SCALE;
|
||||
|
||||
pango_font_metrics_unref(metrics);
|
||||
g_object_unref(context);
|
||||
|
||||
return font;
|
||||
}
|
||||
#else
|
||||
/* This function is an implementation detail. Library users should use
|
||||
* drw_fontset_create instead.
|
||||
*/
|
||||
|
@ -136,6 +191,7 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
|
|||
die("no font specified.");
|
||||
}
|
||||
|
||||
#if NO_COLOR_EMOJI_PATCH
|
||||
/* 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
|
||||
|
@ -148,6 +204,7 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
|
|||
XftFontClose(drw->dpy, xfont);
|
||||
return NULL;
|
||||
}
|
||||
#endif // NO_COLOR_EMOJI_PATCH
|
||||
|
||||
font = ecalloc(1, sizeof(Fnt));
|
||||
font->xfont = xfont;
|
||||
|
@ -157,18 +214,38 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
|
|||
|
||||
return font;
|
||||
}
|
||||
#endif // PANGO_PATCH
|
||||
|
||||
static void
|
||||
xfont_free(Fnt *font)
|
||||
{
|
||||
if (!font)
|
||||
return;
|
||||
#if PANGO_PATCH
|
||||
if (font->layout)
|
||||
g_object_unref(font->layout);
|
||||
#else
|
||||
if (font->pattern)
|
||||
FcPatternDestroy(font->pattern);
|
||||
XftFontClose(font->dpy, font->xfont);
|
||||
#endif // PANGO_PATCH
|
||||
free(font);
|
||||
}
|
||||
|
||||
#if PANGO_PATCH
|
||||
Fnt*
|
||||
drw_font_create(Drw* drw, const char font[])
|
||||
{
|
||||
Fnt *fnt = NULL;
|
||||
|
||||
if (!drw || !font)
|
||||
return NULL;
|
||||
|
||||
fnt = xfont_create(drw, font);
|
||||
|
||||
return (drw->font = fnt);
|
||||
}
|
||||
#else
|
||||
Fnt*
|
||||
drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
|
||||
{
|
||||
|
@ -186,7 +263,16 @@ drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
|
|||
}
|
||||
return (drw->fonts = ret);
|
||||
}
|
||||
#endif // PANGO_PATCH
|
||||
|
||||
#if PANGO_PATCH
|
||||
void
|
||||
drw_font_free(Fnt *font)
|
||||
{
|
||||
if (font)
|
||||
xfont_free(font);
|
||||
}
|
||||
#else
|
||||
void
|
||||
drw_fontset_free(Fnt *font)
|
||||
{
|
||||
|
@ -195,24 +281,40 @@ drw_fontset_free(Fnt *font)
|
|||
xfont_free(font);
|
||||
}
|
||||
}
|
||||
#endif // PANGO_PATCH
|
||||
|
||||
void
|
||||
#if ALPHA_PATCH
|
||||
drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha)
|
||||
#else
|
||||
drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
|
||||
#endif // ALPHA_PATCH
|
||||
{
|
||||
if (!drw || !dest || !clrname)
|
||||
return;
|
||||
|
||||
#if ALPHA_PATCH
|
||||
if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
|
||||
clrname, dest))
|
||||
die("error, cannot allocate color '%s'", clrname);
|
||||
|
||||
dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
|
||||
#else
|
||||
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
|
||||
DefaultColormap(drw->dpy, drw->screen),
|
||||
clrname, dest))
|
||||
die("error, cannot allocate color '%s'", clrname);
|
||||
#endif // ALPHA_PATCH
|
||||
}
|
||||
|
||||
/* Wrapper to create color schemes. The caller has to call free(3) on the
|
||||
* returned color scheme when done using it. */
|
||||
Clr *
|
||||
#if ALPHA_PATCH
|
||||
drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount)
|
||||
#else
|
||||
drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
|
||||
#endif // ALPHA_PATCH
|
||||
{
|
||||
size_t i;
|
||||
Clr *ret;
|
||||
|
@ -222,16 +324,22 @@ drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], si
|
|||
return NULL;
|
||||
|
||||
for (i = 0; i < clrcount; i++)
|
||||
#if ALPHA_PATCH
|
||||
drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
|
||||
#else
|
||||
drw_clr_create(drw, &ret[i], clrnames[i]);
|
||||
#endif // ALPHA_PATCH
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if !PANGO_PATCH
|
||||
void
|
||||
drw_setfontset(Drw *drw, Fnt *set)
|
||||
{
|
||||
if (drw)
|
||||
drw->fonts = set;
|
||||
}
|
||||
#endif // PANGO_PATCH
|
||||
|
||||
void
|
||||
drw_setscheme(Drw *drw, Clr *scm)
|
||||
|
@ -252,15 +360,80 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int
|
|||
XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
|
||||
}
|
||||
|
||||
#if PANGO_PATCH
|
||||
int
|
||||
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
|
||||
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup)
|
||||
{
|
||||
char buf[1024];
|
||||
int ty;
|
||||
unsigned int ew;
|
||||
XftDraw *d = NULL;
|
||||
Fnt *usedfont, *curfont, *nextfont;
|
||||
size_t i, len;
|
||||
int render = x || y || w || h;
|
||||
|
||||
if (!drw || (render && !drw->scheme) || !text || !drw->font)
|
||||
return 0;
|
||||
|
||||
if (!render) {
|
||||
w = invert ? invert : ~invert;
|
||||
} else {
|
||||
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
|
||||
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||||
#if ALPHA_PATCH
|
||||
d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
|
||||
#else
|
||||
d = XftDrawCreate(drw->dpy, drw->drawable,
|
||||
DefaultVisual(drw->dpy, drw->screen),
|
||||
DefaultColormap(drw->dpy, drw->screen));
|
||||
#endif // ALPHA_PATCH
|
||||
x += lpad;
|
||||
w -= lpad;
|
||||
}
|
||||
|
||||
len = strlen(text);
|
||||
|
||||
if (len) {
|
||||
drw_font_getexts(drw->font, text, len, &ew, NULL, markup);
|
||||
/* shorten text if necessary */
|
||||
for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--)
|
||||
drw_font_getexts(drw->font, text, len, &ew, NULL, markup);
|
||||
|
||||
if (len) {
|
||||
memcpy(buf, text, len);
|
||||
buf[len] = '\0';
|
||||
if (len < strlen(text))
|
||||
for (i = len; i && i > len - 3; buf[--i] = '.')
|
||||
; /* NOP */
|
||||
|
||||
if (render) {
|
||||
ty = y + (h - drw->font->h) / 2;
|
||||
if (markup)
|
||||
pango_layout_set_markup(drw->font->layout, buf, len);
|
||||
else
|
||||
pango_layout_set_text(drw->font->layout, buf, len);
|
||||
pango_xft_render_layout(d, &drw->scheme[invert ? ColBg : ColFg],
|
||||
drw->font->layout, x * PANGO_SCALE, ty * PANGO_SCALE);
|
||||
if (markup) /* clear markup attributes */
|
||||
pango_layout_set_attributes(drw->font->layout, NULL);
|
||||
}
|
||||
x += ew;
|
||||
w -= ew;
|
||||
}
|
||||
}
|
||||
|
||||
if (d)
|
||||
XftDrawDestroy(d);
|
||||
|
||||
return x + (render ? w : 0);
|
||||
}
|
||||
#else
|
||||
int
|
||||
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
|
||||
{
|
||||
int i, ty, ellipsis_x = 0;
|
||||
unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len;
|
||||
XftDraw *d = NULL;
|
||||
Fnt *usedfont, *curfont, *nextfont;
|
||||
int utf8strlen, utf8charlen, render = x || y || w || h;
|
||||
long utf8codepoint = 0;
|
||||
const char *utf8str;
|
||||
|
@ -268,24 +441,37 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
FcPattern *fcpattern;
|
||||
FcPattern *match;
|
||||
XftResult result;
|
||||
int charexists = 0;
|
||||
int charexists = 0, overflow = 0;
|
||||
/* keep track of a couple codepoints for which we have no match. */
|
||||
enum { nomatches_len = 64 };
|
||||
static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches;
|
||||
const char *ellipsis = "...";
|
||||
static unsigned int ellipsis_width = 0;
|
||||
|
||||
if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
|
||||
if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
|
||||
return 0;
|
||||
|
||||
if (!render) {
|
||||
w = ~w;
|
||||
w = invert ? invert : ~invert;
|
||||
} else {
|
||||
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
|
||||
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||||
#if ALPHA_PATCH
|
||||
d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
|
||||
#else
|
||||
d = XftDrawCreate(drw->dpy, drw->drawable,
|
||||
DefaultVisual(drw->dpy, drw->screen),
|
||||
DefaultColormap(drw->dpy, drw->screen));
|
||||
#endif // ALPHA_PATCH
|
||||
x += lpad;
|
||||
w -= lpad;
|
||||
}
|
||||
|
||||
usedfont = drw->fonts;
|
||||
if (!ellipsis_width && render)
|
||||
ellipsis_width = drw_fontset_getwidth(drw, ellipsis);
|
||||
while (1) {
|
||||
utf8strlen = 0;
|
||||
ew = ellipsis_len = utf8strlen = 0;
|
||||
utf8str = text;
|
||||
nextfont = NULL;
|
||||
while (*text) {
|
||||
|
@ -293,9 +479,27 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
|
||||
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
|
||||
if (charexists) {
|
||||
if (curfont == usedfont) {
|
||||
drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL);
|
||||
if (ew + ellipsis_width <= w) {
|
||||
/* keep track where the ellipsis still fits */
|
||||
ellipsis_x = x + ew;
|
||||
ellipsis_w = w - ew;
|
||||
ellipsis_len = utf8strlen;
|
||||
}
|
||||
|
||||
if (ew + tmpw > w) {
|
||||
overflow = 1;
|
||||
/* called from drw_fontset_getwidth_clamp():
|
||||
* it wants the width AFTER the overflow
|
||||
*/
|
||||
if (!render)
|
||||
x += tmpw;
|
||||
else
|
||||
utf8strlen = ellipsis_len;
|
||||
} else if (curfont == usedfont) {
|
||||
utf8strlen += utf8charlen;
|
||||
text += utf8charlen;
|
||||
ew += tmpw;
|
||||
} else {
|
||||
nextfont = curfont;
|
||||
}
|
||||
|
@ -303,36 +507,25 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
}
|
||||
}
|
||||
|
||||
if (!charexists || nextfont)
|
||||
if (overflow || !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);
|
||||
usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen);
|
||||
}
|
||||
x += ew;
|
||||
w -= ew;
|
||||
}
|
||||
}
|
||||
if (render && overflow && ellipsis_w)
|
||||
drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, ellipsis, invert);
|
||||
|
||||
if (!*text) {
|
||||
if (!*text || overflow) {
|
||||
break;
|
||||
} else if (nextfont) {
|
||||
charexists = 0;
|
||||
|
@ -342,6 +535,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
* character must be drawn. */
|
||||
charexists = 1;
|
||||
|
||||
for (i = 0; i < nomatches_len; ++i) {
|
||||
/* avoid calling XftFontMatch if we know we won't find a match */
|
||||
if (utf8codepoint == nomatches.codepoint[i])
|
||||
goto no_match;
|
||||
}
|
||||
|
||||
fccharset = FcCharSetCreate();
|
||||
FcCharSetAddChar(fccharset, utf8codepoint);
|
||||
|
||||
|
@ -353,7 +552,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
fcpattern = FcPatternDuplicate(drw->fonts->pattern);
|
||||
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
|
||||
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
|
||||
#if NO_COLOR_EMOJI_PATCH
|
||||
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
|
||||
#endif // NO_COLOR_EMOJI_PATCH
|
||||
|
||||
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
|
||||
FcDefaultSubstitute(fcpattern);
|
||||
|
@ -370,6 +571,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
curfont->next = usedfont;
|
||||
} else {
|
||||
xfont_free(usedfont);
|
||||
nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint;
|
||||
no_match:
|
||||
usedfont = drw->fonts;
|
||||
}
|
||||
}
|
||||
|
@ -380,6 +583,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
|
||||
return x + (render ? w : 0);
|
||||
}
|
||||
#endif // PANGO_PATCH
|
||||
|
||||
void
|
||||
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
|
||||
|
@ -391,6 +595,24 @@ drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
|
|||
XSync(drw->dpy, False);
|
||||
}
|
||||
|
||||
#if PANGO_PATCH
|
||||
unsigned int
|
||||
drw_font_getwidth(Drw *drw, const char *text, Bool markup)
|
||||
{
|
||||
if (!drw || !drw->font || !text)
|
||||
return 0;
|
||||
return drw_text(drw, 0, 0, 0, 0, 0, text, 0, markup);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n)
|
||||
{
|
||||
unsigned int tmp = 0;
|
||||
if (drw && drw->font && text && n)
|
||||
tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n, True);
|
||||
return MIN(n, tmp);
|
||||
}
|
||||
#else
|
||||
unsigned int
|
||||
drw_fontset_getwidth(Drw *drw, const char *text)
|
||||
{
|
||||
|
@ -399,6 +621,37 @@ drw_fontset_getwidth(Drw *drw, const char *text)
|
|||
return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n)
|
||||
{
|
||||
unsigned int tmp = 0;
|
||||
if (drw && drw->fonts && text && n)
|
||||
tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n);
|
||||
return MIN(n, tmp);
|
||||
}
|
||||
#endif // PANGO_PATCH
|
||||
|
||||
#if PANGO_PATCH
|
||||
void
|
||||
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup)
|
||||
{
|
||||
if (!font || !text)
|
||||
return;
|
||||
|
||||
PangoRectangle r;
|
||||
if (markup)
|
||||
pango_layout_set_markup(font->layout, text, len);
|
||||
else
|
||||
pango_layout_set_text(font->layout, text, len);
|
||||
pango_layout_get_extents(font->layout, 0, &r);
|
||||
if (markup) /* clear markup attributes */
|
||||
pango_layout_set_attributes(font->layout, NULL);
|
||||
if (w)
|
||||
*w = r.width / PANGO_SCALE;
|
||||
if (h)
|
||||
*h = font->h;
|
||||
}
|
||||
#else
|
||||
void
|
||||
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
|
||||
{
|
||||
|
@ -413,6 +666,7 @@ drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w,
|
|||
if (h)
|
||||
*h = font->h;
|
||||
}
|
||||
#endif // PANGO_PATCH
|
||||
|
||||
Cur *
|
||||
drw_cur_create(Drw *drw, int shape)
|
||||
|
@ -436,3 +690,7 @@ drw_cur_free(Drw *drw, Cur *cursor)
|
|||
XFreeCursor(drw->dpy, cursor->cursor);
|
||||
free(cursor);
|
||||
}
|
||||
|
||||
#if SCROLL_PATCH
|
||||
#include "patch/scroll.c"
|
||||
#endif
|
|
@ -1,5 +1,10 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#if PANGO_PATCH
|
||||
#include <pango/pango.h>
|
||||
#include <pango/pangoxft.h>
|
||||
#endif // PANGO_PATCH
|
||||
|
||||
typedef struct {
|
||||
Cursor cursor;
|
||||
} Cur;
|
||||
|
@ -7,9 +12,13 @@ typedef struct {
|
|||
typedef struct Fnt {
|
||||
Display *dpy;
|
||||
unsigned int h;
|
||||
#if PANGO_PATCH
|
||||
PangoLayout *layout;
|
||||
#else
|
||||
XftFont *xfont;
|
||||
FcPattern *pattern;
|
||||
struct Fnt *next;
|
||||
#endif // PANGO_PATCH
|
||||
} Fnt;
|
||||
|
||||
enum { ColFg, ColBg }; /* Clr scheme index */
|
||||
|
@ -20,41 +29,75 @@ typedef struct {
|
|||
Display *dpy;
|
||||
int screen;
|
||||
Window root;
|
||||
#if ALPHA_PATCH
|
||||
Visual *visual;
|
||||
unsigned int depth;
|
||||
Colormap cmap;
|
||||
#endif // ALPHA_PATCH
|
||||
Drawable drawable;
|
||||
GC gc;
|
||||
Clr *scheme;
|
||||
#if PANGO_PATCH
|
||||
Fnt *font;
|
||||
#else
|
||||
Fnt *fonts;
|
||||
#endif // PANGO_PATCH
|
||||
} Drw;
|
||||
|
||||
/* Drawable abstraction */
|
||||
#if ALPHA_PATCH
|
||||
Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap);
|
||||
#else
|
||||
Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
|
||||
#endif // ALPHA_PATCH
|
||||
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
|
||||
void drw_free(Drw *drw);
|
||||
|
||||
/* Fnt abstraction */
|
||||
#if PANGO_PATCH
|
||||
Fnt *drw_font_create(Drw* drw, const char font[]);
|
||||
void drw_font_free(Fnt* set);
|
||||
unsigned int drw_font_getwidth(Drw *drw, const char *text, Bool markup);
|
||||
unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n);
|
||||
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup);
|
||||
#else
|
||||
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);
|
||||
unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n);
|
||||
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
|
||||
#endif // PANGO_PATCH
|
||||
|
||||
/* Colorscheme abstraction */
|
||||
#if ALPHA_PATCH
|
||||
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha);
|
||||
Clr *drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount);
|
||||
#else
|
||||
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
|
||||
Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
|
||||
#endif // ALPHA_PATCH
|
||||
|
||||
/* Cursor abstraction */
|
||||
Cur *drw_cur_create(Drw *drw, int shape);
|
||||
void drw_cur_free(Drw *drw, Cur *cursor);
|
||||
|
||||
/* Drawing context manipulation */
|
||||
#if !PANGO_PATCH
|
||||
void drw_setfontset(Drw *drw, Fnt *set);
|
||||
#endif // PANGO_PATCH
|
||||
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);
|
||||
#if PANGO_PATCH
|
||||
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup);
|
||||
#else
|
||||
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
|
||||
#endif // PANGO_PATCH
|
||||
|
||||
/* Map functions */
|
||||
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
|
||||
|
||||
#if SCROLL_PATCH
|
||||
#include "patch/scroll.h"
|
||||
#endif
|
8
dmenu-flexipatch/patch/center.c
Normal file
8
dmenu-flexipatch/patch/center.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
static int
|
||||
max_textw(void)
|
||||
{
|
||||
int len = 0;
|
||||
for (struct item *item = items; item && item->text; item++)
|
||||
len = MAX(TEXTW(item->text), len);
|
||||
return len;
|
||||
}
|
91
dmenu-flexipatch/patch/dynamicoptions.c
Normal file
91
dmenu-flexipatch/patch/dynamicoptions.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
static void
|
||||
refreshoptions()
|
||||
{
|
||||
int dynlen = strlen(dynamic);
|
||||
char* cmd= malloc(dynlen + strlen(text) + 2);
|
||||
if (cmd == NULL)
|
||||
die("malloc:");
|
||||
sprintf(cmd, "%s %s", dynamic, text);
|
||||
FILE *stream = popen(cmd, "r");
|
||||
if (!stream)
|
||||
die("popen(%s):", cmd);
|
||||
readstream(stream);
|
||||
int pc = pclose(stream);
|
||||
if (pc == -1)
|
||||
die("pclose:");
|
||||
free(cmd);
|
||||
curr = sel = items;
|
||||
}
|
||||
|
||||
static void
|
||||
readstream(FILE* stream)
|
||||
{
|
||||
char buf[sizeof text], *p;
|
||||
size_t i, imax = 0, size = 0;
|
||||
unsigned int tmpmax = 0;
|
||||
|
||||
/* read each line from stdin and add it to the item list */
|
||||
for (i = 0; fgets(buf, sizeof buf, stream); i++) {
|
||||
if (i + 1 >= size / sizeof *items)
|
||||
if (!(items = realloc(items, (size += BUFSIZ))))
|
||||
die("cannot realloc %u bytes:", size);
|
||||
if ((p = strchr(buf, '\n')))
|
||||
*p = '\0';
|
||||
if (!(items[i].text = strdup(buf)))
|
||||
die("cannot strdup %u bytes:", strlen(buf) + 1);
|
||||
#if SEPARATOR_PATCH
|
||||
if (separator && (p = separator_greedy ?
|
||||
strrchr(items[i].text, separator) : strchr(items[i].text, separator))) {
|
||||
*p = '\0';
|
||||
items[i].text_output = ++p;
|
||||
} else {
|
||||
items[i].text_output = items[i].text;
|
||||
}
|
||||
if (separator_reverse) {
|
||||
p = items[i].text;
|
||||
items[i].text = items[i].text_output;
|
||||
items[i].text_output = p;
|
||||
}
|
||||
#elif TSV_PATCH
|
||||
if ((p = strchr(buf, '\t')))
|
||||
*p = '\0';
|
||||
if (!(items[i].stext = strdup(buf)))
|
||||
die("cannot strdup %u bytes:", strlen(buf) + 1);
|
||||
#endif // TSV_PATCH
|
||||
#if MULTI_SELECTION_PATCH
|
||||
items[i].id = i;
|
||||
#else
|
||||
items[i].out = 0;
|
||||
#endif // MULTI_SELECTION_PATCH
|
||||
#if HIGHPRIORITY_PATCH
|
||||
items[i].hp = arrayhas(hpitems, hplength, items[i].text);
|
||||
#endif // HIGHPRIORITY_PATCH
|
||||
#if PANGO_PATCH
|
||||
drw_font_getexts(drw->font, buf, strlen(buf), &tmpmax, NULL, True);
|
||||
#else
|
||||
drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL);
|
||||
#endif // PANGO_PATCH
|
||||
if (tmpmax > inputw) {
|
||||
inputw = tmpmax;
|
||||
imax = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the command did not give any output at all, then do not clear the existing items */
|
||||
if (!i)
|
||||
return;
|
||||
|
||||
if (items)
|
||||
items[i].text = NULL;
|
||||
#if PANGO_PATCH
|
||||
inputw = items ? TEXTWM(items[imax].text) : 0;
|
||||
#else
|
||||
inputw = items ? TEXTW(items[imax].text) : 0;
|
||||
#endif // PANGO_PATCH
|
||||
if (!dynamic || !*dynamic)
|
||||
lines = MIN(lines, i);
|
||||
else {
|
||||
text[0] = '\0';
|
||||
cursor = 0;
|
||||
}
|
||||
}
|
2
dmenu-flexipatch/patch/dynamicoptions.h
Normal file
2
dmenu-flexipatch/patch/dynamicoptions.h
Normal file
|
@ -0,0 +1,2 @@
|
|||
static void refreshoptions();
|
||||
static void readstream(FILE* stream);
|
66
dmenu-flexipatch/patch/fuzzyhighlight.c
Normal file
66
dmenu-flexipatch/patch/fuzzyhighlight.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
static void
|
||||
#if EMOJI_HIGHLIGHT_PATCH
|
||||
drawhighlights(struct item *item, char *output, int x, int y, int maxw)
|
||||
#else
|
||||
drawhighlights(struct item *item, int x, int y, int maxw)
|
||||
#endif // EMOJI_HIGHLIGHT_PATCH
|
||||
{
|
||||
int i, indent;
|
||||
char *highlight;
|
||||
char c;
|
||||
|
||||
#if EMOJI_HIGHLIGHT_PATCH
|
||||
char *itemtext = output;
|
||||
#elif TSV_PATCH && !SEPARATOR_PATCH
|
||||
char *itemtext = item->stext;
|
||||
#else
|
||||
char *itemtext = item->text;
|
||||
#endif // TSV_PATCH
|
||||
|
||||
if (!(strlen(itemtext) && strlen(text)))
|
||||
return;
|
||||
|
||||
/* Do not highlight items scheduled for output */
|
||||
#if MULTI_SELECTION_PATCH
|
||||
if (issel(item->id))
|
||||
return;
|
||||
#else
|
||||
if (item->out)
|
||||
return;
|
||||
#endif // MULTI_SELECTION_PATCH
|
||||
|
||||
drw_setscheme(drw, scheme[item == sel
|
||||
? SchemeSelHighlight
|
||||
: SchemeNormHighlight]);
|
||||
for (i = 0, highlight = itemtext; *highlight && text[i];) {
|
||||
#if FUZZYMATCH_PATCH
|
||||
if (!fstrncmp(&(*highlight), &text[i], 1))
|
||||
#else
|
||||
if (*highlight == text[i])
|
||||
#endif // FUZZYMATCH_PATCH
|
||||
{
|
||||
/* get indentation */
|
||||
c = *highlight;
|
||||
*highlight = '\0';
|
||||
indent = TEXTW(itemtext) - lrpad;
|
||||
*highlight = c;
|
||||
|
||||
/* highlight character */
|
||||
c = highlight[1];
|
||||
highlight[1] = '\0';
|
||||
drw_text(
|
||||
drw,
|
||||
x + indent + (lrpad / 2),
|
||||
y,
|
||||
MIN(maxw - indent - lrpad, TEXTW(highlight) - lrpad),
|
||||
bh, 0, highlight, 0
|
||||
#if PANGO_PATCH
|
||||
, True
|
||||
#endif // PANGO_PATCH
|
||||
);
|
||||
highlight[1] = c;
|
||||
i++;
|
||||
}
|
||||
highlight++;
|
||||
}
|
||||
}
|
115
dmenu-flexipatch/patch/fuzzymatch.c
Normal file
115
dmenu-flexipatch/patch/fuzzymatch.c
Normal file
|
@ -0,0 +1,115 @@
|
|||
#include <math.h>
|
||||
|
||||
int
|
||||
compare_distance(const void *a, const void *b)
|
||||
{
|
||||
struct item *da = *(struct item **) a;
|
||||
struct item *db = *(struct item **) b;
|
||||
|
||||
if (!db)
|
||||
return 1;
|
||||
if (!da)
|
||||
return -1;
|
||||
|
||||
return da->distance == db->distance ? 0 : da->distance < db->distance ? -1 : 1;
|
||||
}
|
||||
|
||||
void
|
||||
fuzzymatch(void)
|
||||
{
|
||||
/* bang - we have so much memory */
|
||||
struct item *it;
|
||||
struct item **fuzzymatches = NULL;
|
||||
char c;
|
||||
int number_of_matches = 0, i, pidx, sidx, eidx;
|
||||
int text_len = strlen(text), itext_len;
|
||||
#if HIGHPRIORITY_PATCH
|
||||
struct item *lhpprefix, *hpprefixend;
|
||||
lhpprefix = hpprefixend = NULL;
|
||||
#endif // HIGHPRIORITY_PATCH
|
||||
matches = matchend = NULL;
|
||||
|
||||
/* walk through all items */
|
||||
for (it = items; it && it->text; it++) {
|
||||
if (text_len) {
|
||||
itext_len = strlen(it->text);
|
||||
pidx = 0; /* pointer */
|
||||
sidx = eidx = -1; /* start of match, end of match */
|
||||
/* walk through item text */
|
||||
for (i = 0; i < itext_len && (c = it->text[i]); i++) {
|
||||
/* fuzzy match pattern */
|
||||
if (!fstrncmp(&text[pidx], &c, 1)) {
|
||||
if (sidx == -1)
|
||||
sidx = i;
|
||||
pidx++;
|
||||
if (pidx == text_len) {
|
||||
eidx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* build list of matches */
|
||||
if (eidx != -1) {
|
||||
/* compute distance */
|
||||
/* add penalty if match starts late (log(sidx+2))
|
||||
* add penalty for long a match without many matching characters */
|
||||
it->distance = log(sidx + 2) + (double)(eidx - sidx - text_len);
|
||||
/* fprintf(stderr, "distance %s %f\n", it->text, it->distance); */
|
||||
appenditem(it, &matches, &matchend);
|
||||
number_of_matches++;
|
||||
}
|
||||
} else {
|
||||
appenditem(it, &matches, &matchend);
|
||||
}
|
||||
}
|
||||
|
||||
if (number_of_matches) {
|
||||
/* initialize array with matches */
|
||||
if (!(fuzzymatches = realloc(fuzzymatches, number_of_matches * sizeof(struct item*))))
|
||||
die("cannot realloc %u bytes:", number_of_matches * sizeof(struct item*));
|
||||
for (i = 0, it = matches; it && i < number_of_matches; i++, it = it->right) {
|
||||
fuzzymatches[i] = it;
|
||||
}
|
||||
|
||||
#if NO_SORT_PATCH
|
||||
if (sortmatches)
|
||||
#endif // NO_SORT_PATCH
|
||||
/* sort matches according to distance */
|
||||
qsort(fuzzymatches, number_of_matches, sizeof(struct item*), compare_distance);
|
||||
/* rebuild list of matches */
|
||||
matches = matchend = NULL;
|
||||
for (i = 0, it = fuzzymatches[i]; i < number_of_matches && it && \
|
||||
it->text; i++, it = fuzzymatches[i]) {
|
||||
#if HIGHPRIORITY_PATCH
|
||||
#if NO_SORT_PATCH
|
||||
if (sortmatches && it->hp)
|
||||
#else
|
||||
if (it->hp)
|
||||
#endif // NO_SORT_PATCH
|
||||
appenditem(it, &lhpprefix, &hpprefixend);
|
||||
else
|
||||
appenditem(it, &matches, &matchend);
|
||||
#else
|
||||
appenditem(it, &matches, &matchend);
|
||||
#endif // HIGHPRIORITY_PATCH
|
||||
}
|
||||
free(fuzzymatches);
|
||||
}
|
||||
#if HIGHPRIORITY_PATCH
|
||||
if (lhpprefix) {
|
||||
hpprefixend->right = matches;
|
||||
matches = lhpprefix;
|
||||
}
|
||||
#endif // HIGHPRIORITY_PATCH
|
||||
curr = sel = matches;
|
||||
|
||||
#if INSTANT_PATCH
|
||||
if (instant && matches && matches==matchend) {
|
||||
puts(matches->text);
|
||||
cleanup();
|
||||
exit(0);
|
||||
}
|
||||
#endif // INSTANT_PATCH
|
||||
|
||||
calcoffsets();
|
||||
}
|
39
dmenu-flexipatch/patch/fzfexpect.c
Normal file
39
dmenu-flexipatch/patch/fzfexpect.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
static char *expected;
|
||||
#if MULTI_SELECTION_PATCH
|
||||
void
|
||||
expect(char *expect, XKeyEvent *ev)
|
||||
{
|
||||
if (sel && expected && strstr(expected, expect)) {
|
||||
if (expected && sel && !(ev->state & ShiftMask))
|
||||
puts(expect);
|
||||
for (int i = 0; i < selidsize; i++)
|
||||
if (selid[i] != -1 && (!sel || sel->id != selid[i]))
|
||||
puts(items[selid[i]].text);
|
||||
if (sel && !(ev->state & ShiftMask)) {
|
||||
puts(sel->text);
|
||||
} else
|
||||
puts(text);
|
||||
cleanup();
|
||||
exit(1);
|
||||
} else if (!sel && expected && strstr(expected, expect)) {
|
||||
puts(expect);
|
||||
cleanup();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void
|
||||
expect(char *expect, XKeyEvent *ignored)
|
||||
{
|
||||
if (sel && expected && strstr(expected, expect)) {
|
||||
puts(expect);
|
||||
puts(sel->text);
|
||||
cleanup();
|
||||
exit(1);
|
||||
} else if (!sel && expected && strstr(expected, expect)){
|
||||
puts(expect);
|
||||
cleanup();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#endif // MULTI_SELECTION_PATCH
|
1
dmenu-flexipatch/patch/fzfexpect.h
Normal file
1
dmenu-flexipatch/patch/fzfexpect.h
Normal file
|
@ -0,0 +1 @@
|
|||
static void expect(char *expect, XKeyEvent *ev);
|
60
dmenu-flexipatch/patch/highlight.c
Normal file
60
dmenu-flexipatch/patch/highlight.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
static void
|
||||
#if EMOJI_HIGHLIGHT_PATCH
|
||||
drawhighlights(struct item *item, char *output, int x, int y, int maxw)
|
||||
#else
|
||||
drawhighlights(struct item *item, int x, int y, int maxw)
|
||||
#endif // EMOJI_HIGHLIGHT_PATCH
|
||||
{
|
||||
char restorechar, tokens[sizeof text], *highlight, *token;
|
||||
int indentx, highlightlen;
|
||||
#if EMOJI_HIGHLIGHT_PATCH
|
||||
char *itemtext = output;
|
||||
#elif TSV_PATCH && !SEPARATOR_PATCH
|
||||
char *itemtext = item->stext;
|
||||
#else
|
||||
char *itemtext = item->text;
|
||||
#endif // EMOJI_HIGHLIGHT_PATCH | TSV_PATCH
|
||||
|
||||
/* Do not highlight items scheduled for output */
|
||||
#if MULTI_SELECTION_PATCH
|
||||
if (issel(item->id))
|
||||
return;
|
||||
#else
|
||||
if (item->out)
|
||||
return;
|
||||
#endif // MULTI_SELECTION_PATCH
|
||||
|
||||
drw_setscheme(drw, scheme[item == sel ? SchemeSelHighlight : SchemeNormHighlight]);
|
||||
strcpy(tokens, text);
|
||||
for (token = strtok(tokens, " "); token; token = strtok(NULL, " ")) {
|
||||
highlight = fstrstr(itemtext, token);
|
||||
while (highlight) {
|
||||
// Move item str end, calc width for highlight indent, & restore
|
||||
highlightlen = highlight - itemtext;
|
||||
restorechar = *highlight;
|
||||
itemtext[highlightlen] = '\0';
|
||||
indentx = TEXTW(itemtext);
|
||||
itemtext[highlightlen] = restorechar;
|
||||
|
||||
// Move highlight str end, draw highlight, & restore
|
||||
restorechar = highlight[strlen(token)];
|
||||
highlight[strlen(token)] = '\0';
|
||||
if (indentx - (lrpad / 2) - 1 < maxw)
|
||||
drw_text(
|
||||
drw,
|
||||
x + indentx - (lrpad / 2) - 1,
|
||||
y,
|
||||
MIN(maxw - indentx, TEXTW(highlight) - lrpad),
|
||||
bh, 0, highlight, 0
|
||||
#if PANGO_PATCH
|
||||
, True
|
||||
#endif // PANGO_PATCH
|
||||
);
|
||||
highlight[strlen(token)] = restorechar;
|
||||
|
||||
if (strlen(highlight) - strlen(token) < strlen(token))
|
||||
break;
|
||||
highlight = fstrstr(highlight + strlen(token), token);
|
||||
}
|
||||
}
|
||||
}
|
35
dmenu-flexipatch/patch/highpriority.c
Normal file
35
dmenu-flexipatch/patch/highpriority.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
static char **hpitems = NULL;
|
||||
static int hplength = 0;
|
||||
|
||||
static char **
|
||||
tokenize(char *source, const char *delim, int *llen)
|
||||
{
|
||||
int listlength = 0, list_size = 0;
|
||||
char **list = NULL, *token;
|
||||
|
||||
token = strtok(source, delim);
|
||||
while (token) {
|
||||
if (listlength + 1 >= list_size) {
|
||||
if (!(list = realloc(list, (list_size += 8) * sizeof(*list))))
|
||||
die("Unable to realloc %zu bytes\n", list_size * sizeof(*list));
|
||||
}
|
||||
if (!(list[listlength] = strdup(token)))
|
||||
die("Unable to strdup %zu bytes\n", strlen(token) + 1);
|
||||
token = strtok(NULL, delim);
|
||||
listlength++;
|
||||
}
|
||||
|
||||
*llen = listlength;
|
||||
return list;
|
||||
}
|
||||
|
||||
static int
|
||||
arrayhas(char **list, int length, char *item) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
int len1 = strlen(list[i]);
|
||||
int len2 = strlen(item);
|
||||
if (fstrncmp(list[i], item, len1 > len2 ? len2 : len1) == 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
2
dmenu-flexipatch/patch/highpriority.h
Normal file
2
dmenu-flexipatch/patch/highpriority.h
Normal file
|
@ -0,0 +1,2 @@
|
|||
static int arrayhas(char **list, int length, char *item);
|
||||
|
38
dmenu-flexipatch/patch/include.c
Normal file
38
dmenu-flexipatch/patch/include.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
#if CENTER_PATCH
|
||||
#include "center.c"
|
||||
#endif
|
||||
#if FUZZYHIGHLIGHT_PATCH
|
||||
#include "fuzzyhighlight.c"
|
||||
#elif HIGHLIGHT_PATCH
|
||||
#include "highlight.c"
|
||||
#endif
|
||||
#if FUZZYMATCH_PATCH
|
||||
#include "fuzzymatch.c"
|
||||
#endif
|
||||
#if FZFEXPECT_PATCH
|
||||
#include "fzfexpect.c"
|
||||
#endif
|
||||
#if HIGHPRIORITY_PATCH
|
||||
#include "highpriority.c"
|
||||
#endif
|
||||
#if DYNAMIC_OPTIONS_PATCH
|
||||
#include "dynamicoptions.c"
|
||||
#endif
|
||||
#if MULTI_SELECTION_PATCH
|
||||
#include "multiselect.c"
|
||||
#endif
|
||||
#if MOUSE_SUPPORT_PATCH
|
||||
#include "mousesupport.c"
|
||||
#endif
|
||||
#if NAVHISTORY_PATCH
|
||||
#include "navhistory.c"
|
||||
#endif
|
||||
#if NON_BLOCKING_STDIN_PATCH
|
||||
#include "nonblockingstdin.c"
|
||||
#endif
|
||||
#if NUMBERS_PATCH
|
||||
#include "numbers.c"
|
||||
#endif
|
||||
#if XRESOURCES_PATCH
|
||||
#include "xresources.c"
|
||||
#endif
|
18
dmenu-flexipatch/patch/include.h
Normal file
18
dmenu-flexipatch/patch/include.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#if DYNAMIC_OPTIONS_PATCH
|
||||
#include "dynamicoptions.h"
|
||||
#endif
|
||||
#if FZFEXPECT_PATCH
|
||||
#include "fzfexpect.h"
|
||||
#endif
|
||||
#if MULTI_SELECTION_PATCH
|
||||
#include "multiselect.h"
|
||||
#endif
|
||||
#if HIGHPRIORITY_PATCH
|
||||
#include "highpriority.h"
|
||||
#endif
|
||||
#if NON_BLOCKING_STDIN_PATCH
|
||||
#include "nonblockingstdin.h"
|
||||
#endif
|
||||
#if NUMBERS_PATCH
|
||||
#include "numbers.h"
|
||||
#endif
|
159
dmenu-flexipatch/patch/mousesupport.c
Normal file
159
dmenu-flexipatch/patch/mousesupport.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
static void
|
||||
buttonpress(XEvent *e)
|
||||
{
|
||||
struct item *item;
|
||||
XButtonPressedEvent *ev = &e->xbutton;
|
||||
int x = 0, y = 0, h = bh, w;
|
||||
|
||||
if (ev->window != win)
|
||||
return;
|
||||
|
||||
/* right-click: exit */
|
||||
if (ev->button == Button3)
|
||||
exit(1);
|
||||
|
||||
if (prompt && *prompt)
|
||||
x += promptw;
|
||||
|
||||
/* input field */
|
||||
w = (lines > 0 || !matches) ? mw - x : inputw;
|
||||
|
||||
/* left-click on input: clear input,
|
||||
* NOTE: if there is no left-arrow the space for < is reserved so
|
||||
* add that to the input width */
|
||||
#if SYMBOLS_PATCH
|
||||
if (ev->button == Button1 &&
|
||||
((lines <= 0 && ev->x >= 0 && ev->x <= x + w +
|
||||
((!prev || !curr->left) ? TEXTW(symbol_1) : 0)) ||
|
||||
(lines > 0 && ev->y >= y && ev->y <= y + h))) {
|
||||
insert(NULL, -cursor);
|
||||
drawmenu();
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (ev->button == Button1 &&
|
||||
((lines <= 0 && ev->x >= 0 && ev->x <= x + w +
|
||||
((!prev || !curr->left) ? TEXTW("<") : 0)) ||
|
||||
(lines > 0 && ev->y >= y && ev->y <= y + h))) {
|
||||
insert(NULL, -cursor);
|
||||
drawmenu();
|
||||
return;
|
||||
}
|
||||
#endif // SYMBOLS_PATCH
|
||||
/* middle-mouse click: paste selection */
|
||||
if (ev->button == Button2) {
|
||||
XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
|
||||
utf8, utf8, win, CurrentTime);
|
||||
drawmenu();
|
||||
return;
|
||||
}
|
||||
/* scroll up */
|
||||
if (ev->button == Button4 && prev) {
|
||||
sel = curr = prev;
|
||||
calcoffsets();
|
||||
drawmenu();
|
||||
return;
|
||||
}
|
||||
/* scroll down */
|
||||
if (ev->button == Button5 && next) {
|
||||
sel = curr = next;
|
||||
calcoffsets();
|
||||
drawmenu();
|
||||
return;
|
||||
}
|
||||
if (ev->button != Button1)
|
||||
return;
|
||||
if (ev->state & ~ControlMask)
|
||||
return;
|
||||
if (lines > 0) {
|
||||
/* vertical list: (ctrl)left-click on item */
|
||||
w = mw - x;
|
||||
for (item = curr; item != next; item = item->right) {
|
||||
y += h;
|
||||
if (ev->y >= y && ev->y <= (y + h)) {
|
||||
#if !MULTI_SELECTION_PATCH
|
||||
puts(item->text);
|
||||
#endif // MULTI_SELECTION_PATCH
|
||||
if (!(ev->state & ControlMask)) {
|
||||
#if MULTI_SELECTION_PATCH
|
||||
sel = item;
|
||||
selsel();
|
||||
printsel(ev->state);
|
||||
#endif // MULTI_SELECTION_PATCH
|
||||
exit(0);
|
||||
}
|
||||
sel = item;
|
||||
if (sel) {
|
||||
#if MULTI_SELECTION_PATCH
|
||||
selsel();
|
||||
#else
|
||||
sel->out = 1;
|
||||
#endif // MULTI_SELECTION_PATCH
|
||||
drawmenu();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (matches) {
|
||||
/* left-click on left arrow */
|
||||
x += inputw;
|
||||
#if SYMBOLS_PATCH
|
||||
w = TEXTW(symbol_1);
|
||||
#else
|
||||
w = TEXTW("<");
|
||||
#endif // SYMBOLS_PATCH
|
||||
if (prev && curr->left) {
|
||||
if (ev->x >= x && ev->x <= x + w) {
|
||||
sel = curr = prev;
|
||||
calcoffsets();
|
||||
drawmenu();
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* horizontal list: (ctrl)left-click on item */
|
||||
for (item = curr; item != next; item = item->right) {
|
||||
x += w;
|
||||
#if SYMBOLS_PATCH
|
||||
w = MIN(TEXTW(item->text), mw - x - TEXTW(symbol_2));
|
||||
#else
|
||||
w = MIN(TEXTW(item->text), mw - x - TEXTW(">"));
|
||||
#endif // SYMBOLS_PATCH
|
||||
if (ev->x >= x && ev->x <= x + w) {
|
||||
#if !MULTI_SELECTION_PATCH
|
||||
puts(item->text);
|
||||
#endif // MULTI_SELECTION_PATCH
|
||||
if (!(ev->state & ControlMask)) {
|
||||
#if MULTI_SELECTION_PATCH
|
||||
sel = item;
|
||||
selsel();
|
||||
printsel(ev->state);
|
||||
#endif // MULTI_SELECTION_PATCH
|
||||
exit(0);
|
||||
}
|
||||
sel = item;
|
||||
if (sel) {
|
||||
#if MULTI_SELECTION_PATCH
|
||||
selsel();
|
||||
#else
|
||||
sel->out = 1;
|
||||
#endif // MULTI_SELECTION_PATCH
|
||||
drawmenu();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* left-click on right arrow */
|
||||
#if SYMBOLS_PATCH
|
||||
w = TEXTW(symbol_2);
|
||||
#else
|
||||
w = TEXTW(">");
|
||||
#endif // SYMBOLS_PATCH
|
||||
x = mw - w;
|
||||
if (next && ev->x >= x && ev->x <= x + w) {
|
||||
sel = curr = next;
|
||||
calcoffsets();
|
||||
drawmenu();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
53
dmenu-flexipatch/patch/multiselect.c
Normal file
53
dmenu-flexipatch/patch/multiselect.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
static int
|
||||
issel(size_t id)
|
||||
{
|
||||
for (int i = 0;i < selidsize;i++)
|
||||
if (selid[i] == id)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
printsel(unsigned int state)
|
||||
{
|
||||
for (int i = 0;i < selidsize;i++)
|
||||
if (selid[i] != -1 && (!sel || sel->id != selid[i])) {
|
||||
#if PRINTINDEX_PATCH
|
||||
if (print_index)
|
||||
printf("%d\n", selid[i]);
|
||||
else
|
||||
#endif // PRINTINDEX_PATCH
|
||||
puts(items[selid[i]].text);
|
||||
}
|
||||
if (sel && !(state & ShiftMask)) {
|
||||
#if PRINTINDEX_PATCH
|
||||
if (print_index)
|
||||
printf("%d\n", sel->index);
|
||||
else
|
||||
#endif // PRINTINDEX_PATCH
|
||||
puts(sel->text);
|
||||
} else
|
||||
puts(text);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
selsel()
|
||||
{
|
||||
if (!sel)
|
||||
return;
|
||||
if (issel(sel->id)) {
|
||||
for (int i = 0; i < selidsize; i++)
|
||||
if (selid[i] == sel->id)
|
||||
selid[i] = -1;
|
||||
} else {
|
||||
for (int i = 0; i < selidsize; i++)
|
||||
if (selid[i] == -1) {
|
||||
selid[i] = sel->id;
|
||||
return;
|
||||
}
|
||||
selidsize++;
|
||||
selid = realloc(selid, (selidsize + 1) * sizeof(int));
|
||||
selid[selidsize - 1] = sel->id;
|
||||
}
|
||||
}
|
1
dmenu-flexipatch/patch/multiselect.h
Normal file
1
dmenu-flexipatch/patch/multiselect.h
Normal file
|
@ -0,0 +1 @@
|
|||
static int issel(size_t id);
|
126
dmenu-flexipatch/patch/navhistory.c
Normal file
126
dmenu-flexipatch/patch/navhistory.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
static char *histfile;
|
||||
static char **history;
|
||||
static size_t histsz, histpos;
|
||||
|
||||
static void
|
||||
loadhistory(void)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
static size_t cap = 0;
|
||||
size_t llen;
|
||||
char *line;
|
||||
|
||||
if (!histfile) {
|
||||
return;
|
||||
}
|
||||
|
||||
fp = fopen(histfile, "r");
|
||||
if (!fp) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
line = NULL;
|
||||
llen = 0;
|
||||
if (-1 == getline(&line, &llen, fp)) {
|
||||
if (ferror(fp)) {
|
||||
die("failed to read history");
|
||||
}
|
||||
free(line);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cap == histsz) {
|
||||
cap += 64 * sizeof(char*);
|
||||
history = realloc(history, cap);
|
||||
if (!history) {
|
||||
die("failed to realloc memory");
|
||||
}
|
||||
}
|
||||
strtok(line, "\n");
|
||||
history[histsz] = line;
|
||||
histsz++;
|
||||
}
|
||||
histpos = histsz;
|
||||
|
||||
if (fclose(fp)) {
|
||||
die("failed to close file %s", histfile);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
navhistory(int dir)
|
||||
{
|
||||
static char def[BUFSIZ];
|
||||
char *p = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
if (!history || histpos + 1 == 0)
|
||||
return;
|
||||
|
||||
if (histsz == histpos) {
|
||||
strncpy(def, text, sizeof(def));
|
||||
}
|
||||
|
||||
switch(dir) {
|
||||
case 1:
|
||||
if (histpos < histsz - 1) {
|
||||
p = history[++histpos];
|
||||
} else if (histpos == histsz - 1) {
|
||||
p = def;
|
||||
histpos++;
|
||||
}
|
||||
break;
|
||||
case -1:
|
||||
if (histpos > 0) {
|
||||
p = history[--histpos];
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (p == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
len = MIN(strlen(p), BUFSIZ - 1);
|
||||
strncpy(text, p, len);
|
||||
text[len] = '\0';
|
||||
cursor = len;
|
||||
match();
|
||||
}
|
||||
|
||||
static void
|
||||
savehistory(char *input)
|
||||
{
|
||||
unsigned int i;
|
||||
FILE *fp;
|
||||
|
||||
if (!histfile ||
|
||||
0 == maxhist ||
|
||||
0 == strlen(input)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
fp = fopen(histfile, "w");
|
||||
if (!fp) {
|
||||
die("failed to open %s", histfile);
|
||||
}
|
||||
for (i = histsz < maxhist ? 0 : histsz - maxhist; i < histsz; i++) {
|
||||
if (0 >= fprintf(fp, "%s\n", history[i])) {
|
||||
die("failed to write to %s", histfile);
|
||||
}
|
||||
}
|
||||
if (histsz == 0 || !histnodup || (histsz > 0 && strcmp(input, history[histsz-1]) != 0)) { /* TODO */
|
||||
if (0 >= fputs(input, fp)) {
|
||||
die("failed to write to %s", histfile);
|
||||
}
|
||||
}
|
||||
if (fclose(fp)) {
|
||||
die("failed to close file %s", histfile);
|
||||
}
|
||||
|
||||
out:
|
||||
for (i = 0; i < histsz; i++) {
|
||||
free(history[i]);
|
||||
}
|
||||
free(history);
|
||||
}
|
68
dmenu-flexipatch/patch/nonblockingstdin.c
Normal file
68
dmenu-flexipatch/patch/nonblockingstdin.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
static void
|
||||
readstdin(void)
|
||||
{
|
||||
static size_t max = 0;
|
||||
static struct item **end = &items;
|
||||
|
||||
char buf[sizeof text], *p, *maxstr;
|
||||
struct item *item;
|
||||
|
||||
#if PASSWORD_PATCH
|
||||
if (passwd) {
|
||||
inputw = lines = 0;
|
||||
return;
|
||||
}
|
||||
#endif // PASSWORD_PATCH
|
||||
|
||||
/* read each line from stdin and add it to the item list */
|
||||
while (fgets(buf, sizeof buf, stdin)) {
|
||||
if (!(item = malloc(sizeof *item)))
|
||||
die("cannot malloc %u bytes:", sizeof *item);
|
||||
if ((p = strchr(buf, '\n')))
|
||||
*p = '\0';
|
||||
if (!(item->text = strdup(buf)))
|
||||
die("cannot strdup %u bytes:", strlen(buf)+1);
|
||||
if (strlen(item->text) > max) {
|
||||
max = strlen(maxstr = item->text);
|
||||
#if PANGO_PATCH
|
||||
inputw = maxstr ? TEXTWM(maxstr) : 0;
|
||||
#else
|
||||
inputw = maxstr ? TEXTW(maxstr) : 0;
|
||||
#endif // PANGO_PATCH
|
||||
}
|
||||
*end = item;
|
||||
end = &item->next;
|
||||
item->next = NULL;
|
||||
item->out = 0;
|
||||
}
|
||||
match();
|
||||
drawmenu();
|
||||
}
|
||||
|
||||
static void
|
||||
run(void)
|
||||
{
|
||||
fd_set fds;
|
||||
int flags, xfd = XConnectionNumber(dpy);
|
||||
|
||||
if ((flags = fcntl(0, F_GETFL)) == -1)
|
||||
die("cannot get stdin control flags:");
|
||||
if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1)
|
||||
die("cannot set stdin control flags:");
|
||||
for (;;) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(xfd, &fds);
|
||||
if (!feof(stdin))
|
||||
FD_SET(0, &fds);
|
||||
if (select(xfd + 1, &fds, NULL, NULL, NULL) == -1)
|
||||
die("cannot multiplex input:");
|
||||
if (FD_ISSET(xfd, &fds))
|
||||
readevent();
|
||||
if (FD_ISSET(0, &fds))
|
||||
readstdin();
|
||||
}
|
||||
}
|
1
dmenu-flexipatch/patch/nonblockingstdin.h
Normal file
1
dmenu-flexipatch/patch/nonblockingstdin.h
Normal file
|
@ -0,0 +1 @@
|
|||
static void readevent();
|
16
dmenu-flexipatch/patch/numbers.c
Normal file
16
dmenu-flexipatch/patch/numbers.c
Normal file
|
@ -0,0 +1,16 @@
|
|||
static char numbers[NUMBERSBUFSIZE] = "";
|
||||
|
||||
static void
|
||||
recalculatenumbers()
|
||||
{
|
||||
unsigned int numer = 0, denom = 0;
|
||||
struct item *item;
|
||||
if (matchend) {
|
||||
numer++;
|
||||
for (item = matchend; item && item->left; item = item->left)
|
||||
numer++;
|
||||
}
|
||||
for (item = items; item && item->text; item++)
|
||||
denom++;
|
||||
snprintf(numbers, NUMBERSBUFSIZE, "%d/%d", numer, denom);
|
||||
}
|
4
dmenu-flexipatch/patch/numbers.h
Normal file
4
dmenu-flexipatch/patch/numbers.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#define NUMBERSMAXDIGITS 100
|
||||
#define NUMBERSBUFSIZE (NUMBERSMAXDIGITS * 2) + 1
|
||||
|
||||
static void recalculatenumbers();
|
168
dmenu-flexipatch/patch/scroll.c
Normal file
168
dmenu-flexipatch/patch/scroll.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
int
|
||||
utf8nextchar(const char *str, int len, int i, int inc)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = i + inc; n + inc >= 0 && n + inc <= len
|
||||
&& (str[n] & 0xc0) == 0x80; n += inc)
|
||||
;
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align)
|
||||
{
|
||||
int ty;
|
||||
unsigned int ew;
|
||||
XftDraw *d = NULL;
|
||||
Fnt *usedfont, *curfont, *nextfont;
|
||||
size_t 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;
|
||||
int i, n;
|
||||
|
||||
if (!drw || (render && !drw->scheme) || !text || !drw->fonts || textlen <= 0
|
||||
|| (align != AlignL && align != AlignR))
|
||||
return 0;
|
||||
|
||||
if (!render) {
|
||||
w = ~w;
|
||||
} else {
|
||||
XSetForeground(drw->dpy, drw->gc, drw->scheme[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));
|
||||
}
|
||||
|
||||
usedfont = drw->fonts;
|
||||
i = align == AlignL ? 0 : textlen;
|
||||
x = align == AlignL ? x : x + w;
|
||||
while (1) {
|
||||
utf8strlen = 0;
|
||||
nextfont = NULL;
|
||||
/* if (align == AlignL) */
|
||||
utf8str = text + i;
|
||||
|
||||
while ((align == AlignL && i < textlen) || (align == AlignR && i > 0)) {
|
||||
if (align == AlignL) {
|
||||
utf8charlen = utf8decode(text + i, &utf8codepoint, MIN(textlen - i, UTF_SIZ));
|
||||
if (!utf8charlen) {
|
||||
textlen = i;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
n = utf8nextchar(text, textlen, i, -1);
|
||||
utf8charlen = utf8decode(text + n, &utf8codepoint, MIN(textlen - n, UTF_SIZ));
|
||||
if (!utf8charlen) {
|
||||
textlen -= i;
|
||||
text += i;
|
||||
i = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
|
||||
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
|
||||
if (charexists) {
|
||||
if (curfont == usedfont) {
|
||||
utf8strlen += utf8charlen;
|
||||
i += align == AlignL ? utf8charlen : -utf8charlen;
|
||||
} else {
|
||||
nextfont = curfont;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!charexists || nextfont)
|
||||
break;
|
||||
else
|
||||
charexists = 0;
|
||||
}
|
||||
|
||||
if (align == AlignR)
|
||||
utf8str = text + i;
|
||||
|
||||
if (utf8strlen) {
|
||||
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
|
||||
/* shorten text if necessary */
|
||||
if (align == AlignL) {
|
||||
for (len = utf8strlen; len && ew > w; ) {
|
||||
len = utf8nextchar(utf8str, len, len, -1);
|
||||
drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
|
||||
}
|
||||
} else {
|
||||
for (len = utf8strlen; len && ew > w; ) {
|
||||
n = utf8nextchar(utf8str, len, 0, +1);
|
||||
utf8str += n;
|
||||
len -= n;
|
||||
drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (len) {
|
||||
if (render) {
|
||||
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
|
||||
XftDrawStringUtf8(d, &drw->scheme[ColFg],
|
||||
usedfont->xfont, align == AlignL ? x : x - ew, ty, (XftChar8 *)utf8str, len);
|
||||
}
|
||||
x += align == AlignL ? ew : -ew;
|
||||
w -= ew;
|
||||
}
|
||||
if (len < utf8strlen)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((align == AlignR && i <= 0) || (align == AlignL && i >= textlen)) {
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
3
dmenu-flexipatch/patch/scroll.h
Normal file
3
dmenu-flexipatch/patch/scroll.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
enum { AlignL, AlignR };
|
||||
|
||||
int drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align);
|
90
dmenu-flexipatch/patch/xresources.c
Normal file
90
dmenu-flexipatch/patch/xresources.c
Normal file
|
@ -0,0 +1,90 @@
|
|||
#include <X11/Xresource.h>
|
||||
|
||||
void
|
||||
readxresources(void)
|
||||
{
|
||||
XrmInitialize();
|
||||
|
||||
char* xrm;
|
||||
if ((xrm = XResourceManagerString(drw->dpy))) {
|
||||
char *type;
|
||||
XrmDatabase xdb = XrmGetStringDatabase(xrm);
|
||||
XrmValue xval;
|
||||
|
||||
if (XrmGetResource(xdb, "dmenu.font", "*", &type, &xval))
|
||||
#if PANGO_PATCH
|
||||
strcpy(font, xval.addr);
|
||||
#else
|
||||
fonts[0] = strdup(xval.addr);
|
||||
#endif // PANGO_PATCH
|
||||
#if !PANGO_PATCH
|
||||
else
|
||||
fonts[0] = strdup(fonts[0]);
|
||||
#endif // PANGO_PATCH
|
||||
if (XrmGetResource(xdb, "dmenu.background", "*", &type, &xval))
|
||||
colors[SchemeNorm][ColBg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.foreground", "*", &type, &xval))
|
||||
colors[SchemeNorm][ColFg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.selbackground", "*", &type, &xval))
|
||||
colors[SchemeSel][ColBg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.selforeground", "*", &type, &xval))
|
||||
colors[SchemeSel][ColFg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.outbackground", "*", &type, &xval))
|
||||
colors[SchemeOut][ColBg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.outforeground", "*", &type, &xval))
|
||||
colors[SchemeOut][ColFg] = strdup(xval.addr);
|
||||
#if MORECOLOR_PATCH
|
||||
if (XrmGetResource(xdb, "dmenu.midbackground", "*", &type, &xval))
|
||||
colors[SchemeMid][ColBg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.midforeground", "*", &type, &xval))
|
||||
colors[SchemeMid][ColFg] = strdup(xval.addr);
|
||||
#endif // MORECOLOR_PATCH
|
||||
#if BORDER_PATCH
|
||||
if (XrmGetResource(xdb, "dmenu.bordercolor", "*", &type, &xval))
|
||||
colors[SchemeBorder][ColBg] = strdup(xval.addr);
|
||||
#endif // BORDER_PATCH
|
||||
#if HIGHLIGHT_PATCH || FUZZYHIGHLIGHT_PATCH
|
||||
if (XrmGetResource(xdb, "dmenu.selhlbackground", "*", &type, &xval))
|
||||
colors[SchemeSelHighlight][ColBg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.selhlforeground", "*", &type, &xval))
|
||||
colors[SchemeSelHighlight][ColFg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.hlbackground", "*", &type, &xval))
|
||||
colors[SchemeNormHighlight][ColBg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.hlforeground", "*", &type, &xval))
|
||||
colors[SchemeNormHighlight][ColFg] = strdup(xval.addr);
|
||||
#endif // HIGHLIGHT_PATCH | FUZZYHIGHLIGHT_PATCH
|
||||
#if HIGHPRIORITY_PATCH
|
||||
if (XrmGetResource(xdb, "dmenu.hpbackground", "*", &type, &xval))
|
||||
colors[SchemeHp][ColBg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.hpforeground", "*", &type, &xval))
|
||||
colors[SchemeHp][ColFg] = strdup(xval.addr);
|
||||
#endif // HIGHPRIORITY_PATCH
|
||||
#if EMOJI_HIGHLIGHT_PATCH
|
||||
if (XrmGetResource(xdb, "dmenu.hoverbackground", "*", &type, &xval))
|
||||
colors[SchemeHover][ColBg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.hoverforeground", "*", &type, &xval))
|
||||
colors[SchemeHover][ColFg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.greenbackground", "*", &type, &xval))
|
||||
colors[SchemeGreen][ColBg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.greenforeground", "*", &type, &xval))
|
||||
colors[SchemeGreen][ColFg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.yellowbackground", "*", &type, &xval))
|
||||
colors[SchemeYellow][ColBg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.yellowforeground", "*", &type, &xval))
|
||||
colors[SchemeYellow][ColFg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.bluebackground", "*", &type, &xval))
|
||||
colors[SchemeBlue][ColBg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.blueforeground", "*", &type, &xval))
|
||||
colors[SchemeBlue][ColFg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.purplebackground", "*", &type, &xval))
|
||||
colors[SchemePurple][ColBg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.purpleforeground", "*", &type, &xval))
|
||||
colors[SchemePurple][ColFg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.redbackground", "*", &type, &xval))
|
||||
colors[SchemeRed][ColBg] = strdup(xval.addr);
|
||||
if (XrmGetResource(xdb, "dmenu.redforeground", "*", &type, &xval))
|
||||
colors[SchemeRed][ColFg] = strdup(xval.addr);
|
||||
#endif // EMOJI_HIGHLIGHT_PATCH
|
||||
XrmDestroyDatabase(xdb);
|
||||
}
|
||||
}
|
355
dmenu-flexipatch/patches.def.h
Normal file
355
dmenu-flexipatch/patches.def.h
Normal file
|
@ -0,0 +1,355 @@
|
|||
/* Patches */
|
||||
|
||||
/* The alpha patch adds transparency for the dmenu window.
|
||||
* You need to uncomment the corresponding line in config.mk to use the -lXrender library
|
||||
* when including this patch.
|
||||
* https://github.com/bakkeby/patches/blob/master/dmenu/dmenu-alpha-5.0_20210725_523aa08.diff
|
||||
*/
|
||||
#define ALPHA_PATCH 1
|
||||
|
||||
/* This adds padding for dmenu in similar fashion to the similarly named patch for dwm. The idea
|
||||
* is to have dmenu appear on top of the bar when using said patch in dwm.
|
||||
* https://github.com/bakkeby/patches/wiki/barpadding
|
||||
*/
|
||||
#define BARPADDING_PATCH 0
|
||||
|
||||
/* This patch adds a border around the dmenu window. It is intended to be used with the center
|
||||
* or xyw patches, to make the menu stand out from similarly coloured windows.
|
||||
* http://tools.suckless.org/dmenu/patches/border/
|
||||
*/
|
||||
#define BORDER_PATCH 0
|
||||
|
||||
/* By default the caret in dmenu has a width of 2 pixels. This patch makes that configurable
|
||||
* as well as overridable via a command line option.
|
||||
* https://github.com/DarkSamus669/dmenu-patches/blob/main/dmenu-caretwidth-5.2.diff
|
||||
*/
|
||||
#define CARET_WIDTH_PATCH 1
|
||||
|
||||
/* This patch makes dmenu case-insensitive by default, replacing the
|
||||
* case-insensitive -i option with a case sensitive -s option.
|
||||
* http://tools.suckless.org/dmenu/patches/case-insensitive/
|
||||
*/
|
||||
#define CASEINSENSITIVE_PATCH 1
|
||||
|
||||
/* This patch centers dmenu in the middle of the screen.
|
||||
* https://tools.suckless.org/dmenu/patches/center/
|
||||
*/
|
||||
#define CENTER_PATCH 0
|
||||
|
||||
/* Minor patch to enable the use of Ctrl+v (XA_PRIMARY) and Ctrl+Shift+v (CLIPBOARD) to paste.
|
||||
* By default dmenu only supports Ctrl+y and Ctrl+Shift+y to paste.
|
||||
*/
|
||||
#define CTRL_V_TO_PASTE_PATCH 1
|
||||
|
||||
/* This patch adds a flag (-dy) which makes dmenu run the command given to it whenever input
|
||||
* is changed with the current input as the last argument and update the option list according
|
||||
* to the output of that command.
|
||||
* https://tools.suckless.org/dmenu/patches/dynamicoptions/
|
||||
*/
|
||||
#define DYNAMIC_OPTIONS_PATCH 0
|
||||
|
||||
/* This patch will allow for emojis on the left side with a colored background when selected.
|
||||
* To test this try running:
|
||||
* $ echo -e ":b here\n:p there\n:r and here" | ./dmenu -p "Search..." -W 400 -l 20 -i -h -1
|
||||
* NB: the original patch came embedded with the the xyw patch, the morecolors patch and the
|
||||
* line height patch and as such is intended to be combined with these.
|
||||
* https://tools.suckless.org/dmenu/patches/emoji-highlight/
|
||||
*/
|
||||
#define EMOJI_HIGHLIGHT_PATCH 0
|
||||
|
||||
/* This patch make it so that fuzzy matches gets highlighted and is therefore meant
|
||||
* to be used together with the fuzzymatch patch.
|
||||
* https://tools.suckless.org/dmenu/patches/fuzzyhighlight/
|
||||
*/
|
||||
#define FUZZYHIGHLIGHT_PATCH 1
|
||||
|
||||
/* This patch adds support for fuzzy-matching to dmenu, allowing users to type non-consecutive
|
||||
* portions of the string to be matched.
|
||||
* https://tools.suckless.org/dmenu/patches/fuzzymatch/
|
||||
*/
|
||||
#define FUZZYMATCH_PATCH 1
|
||||
|
||||
/* Adds fzf-like functionality for dmenu.
|
||||
* Refer to https://github.com/DAFF0D11/dafmenu/ for documentation and example use cases.
|
||||
* https://github.com/DAFF0D11/dafmenu/blob/master/patches/dmenu-fzfexpect-5.1.diff
|
||||
*/
|
||||
#define FZFEXPECT_PATCH 0
|
||||
|
||||
/* Allows dmenu's entries to be rendered in a grid by adding a new -g flag to specify
|
||||
* the number of grid columns. The -g and -l options can be used together to create a
|
||||
* G columns * L lines grid.
|
||||
* https://tools.suckless.org/dmenu/patches/grid/
|
||||
*/
|
||||
#define GRID_PATCH 1
|
||||
|
||||
/* This patch adds the ability to move left and right through a grid.
|
||||
* This patch depends on the grid patch.
|
||||
* https://tools.suckless.org/dmenu/patches/gridnav/
|
||||
*/
|
||||
#define GRIDNAV_PATCH 1
|
||||
|
||||
/* This patch highlights the individual characters of matched text for each dmenu list entry.
|
||||
* The fuzzy highlight patch takes precedence over this patch.
|
||||
* https://tools.suckless.org/dmenu/patches/highlight/
|
||||
*/
|
||||
#define HIGHLIGHT_PATCH 0
|
||||
|
||||
/* This will automatically sort the search result so that high priority items are shown first.
|
||||
* https://tools.suckless.org/dmenu/patches/highpriority/
|
||||
*/
|
||||
#define HIGHPRIORITY_PATCH 0
|
||||
|
||||
/* This patch causes dmenu to print out the current text each time a key is pressed.
|
||||
* https://tools.suckless.org/dmenu/patches/incremental/
|
||||
*/
|
||||
#define INCREMENTAL_PATCH 0
|
||||
|
||||
/* This patch adds an option to provide preselected text.
|
||||
* https://tools.suckless.org/dmenu/patches/initialtext/
|
||||
*/
|
||||
#define INITIALTEXT_PATCH 0
|
||||
|
||||
/* This patch adds a flag which will cause dmenu to select an item immediately if there
|
||||
* is only one matching option left.
|
||||
* https://tools.suckless.org/dmenu/patches/instant/
|
||||
*/
|
||||
#define INSTANT_PATCH 1
|
||||
|
||||
/* This patch adds a '-h' option which sets the minimum height of a dmenu line. This helps
|
||||
* integrate dmenu with other UI elements that require a particular vertical size.
|
||||
* http://tools.suckless.org/dmenu/patches/line-height/
|
||||
*/
|
||||
#define LINE_HEIGHT_PATCH 0
|
||||
|
||||
/* This patch adds a -wm flag which sets override_redirect to false; thus letting your window
|
||||
* manager manage the dmenu window.
|
||||
*
|
||||
* This may be helpful in contexts where you don't want to exclusively bind dmenu or want to
|
||||
* treat dmenu more as a "window" rather than as an overlay.
|
||||
* https://tools.suckless.org/dmenu/patches/managed/
|
||||
*/
|
||||
#define MANAGED_PATCH 0
|
||||
|
||||
/* This patch adds an additional color scheme for highlighting entries adjacent to the current
|
||||
* selection.
|
||||
* https://tools.suckless.org/dmenu/patches/morecolor/
|
||||
*/
|
||||
#define MORECOLOR_PATCH 1
|
||||
|
||||
/* This patch adds basic mouse support for dmenu.
|
||||
* https://tools.suckless.org/dmenu/patches/mouse-support/
|
||||
*/
|
||||
#define MOUSE_SUPPORT_PATCH 1
|
||||
|
||||
/* Without this patch when you press Ctrl+Enter dmenu just outputs current item and it is not
|
||||
* possible to undo that.
|
||||
* With this patch dmenu will output all selected items only on exit. It is also possible to
|
||||
* deselect any selected item.
|
||||
* Also refer to the dmenu_run replacement on the below URL that supports multiple selections.
|
||||
*
|
||||
* This patch is not compatible with, and takes precedence over, the json, printinputtext,
|
||||
* pipeout and non-blocking stdin patches.
|
||||
*
|
||||
* https://tools.suckless.org/dmenu/patches/multi-selection/
|
||||
*/
|
||||
#define MULTI_SELECTION_PATCH 1
|
||||
|
||||
/* This patch provides dmenu the ability for history navigation similar to that of bash.
|
||||
*
|
||||
* If you take this patch then it is recommended that you also uncomment the line in the
|
||||
* dmenu_run script which replaces the exec command.
|
||||
*
|
||||
* https://tools.suckless.org/dmenu/patches/navhistory/
|
||||
*/
|
||||
#define NAVHISTORY_PATCH 1
|
||||
|
||||
/* This patch adds back in the workaround for a BadLength error in the Xft library when color
|
||||
* glyphs are used. This is for systems that do not have an updated version of the Xft library
|
||||
* (or generally prefer monochrome fonts).
|
||||
*/
|
||||
#define NO_COLOR_EMOJI_PATCH 0
|
||||
|
||||
/* Adds the -S option to disable sorting menu items after matching. Useful, for example, when menu
|
||||
* items are sorted by their frequency of use (using an external cache) and the most frequently
|
||||
* selected items should always appear first regardless of how they were exact, prefix, or
|
||||
* substring matches.
|
||||
* https://tools.suckless.org/dmenu/patches/no-sort/
|
||||
*/
|
||||
#define NO_SORT_PATCH 0
|
||||
|
||||
/* This is a patch to have dmenu read stdin in a non blocking way, making it wait for input both
|
||||
* from stdin and from X. This means that you can continue feeding dmenu while you type.
|
||||
* This patch is meant to be used along with the incremental patch, so that you can use stdout
|
||||
* to feed stdin.
|
||||
*
|
||||
* This patch is not compatible with the json and multi-selection patches, both of which takes
|
||||
* precedence over this patch.
|
||||
*
|
||||
* https://tools.suckless.org/dmenu/patches/non_blocking_stdin/
|
||||
*/
|
||||
#define NON_BLOCKING_STDIN_PATCH 0
|
||||
|
||||
/* Adds text which displays the number of matched and total items in the top right corner of dmenu.
|
||||
* https://tools.suckless.org/dmenu/patches/numbers/
|
||||
*/
|
||||
#define NUMBERS_PATCH 1
|
||||
|
||||
/* This patch adds simple markup for dmenu using pango markup.
|
||||
* This depends on the pango library v1.44 or greater.
|
||||
* You need to uncomment the corresponding lines in config.mk to use the pango libraries
|
||||
* when including this patch.
|
||||
*
|
||||
* Note that the pango patch is incompatible with the scroll patch and will result in
|
||||
* compilation errors if both are enabled.
|
||||
*
|
||||
* Note that the pango patch does not protect against the BadLength error from Xft
|
||||
* when color glyphs are used, which means that dmenu will crash if color emoji is used.
|
||||
*
|
||||
* If you need color emoji then you may want to install this patched library from the AUR:
|
||||
* https://aur.archlinux.org/packages/libxft-bgra/
|
||||
*
|
||||
* A long term fix for the libXft library is pending approval of this pull request:
|
||||
* https://gitlab.freedesktop.org/xorg/lib/libxft/-/merge_requests/1
|
||||
*
|
||||
* Also see:
|
||||
* https://developer.gnome.org/pygtk/stable/pango-markup-language.html
|
||||
* https://github.com/StillANixRookie/dmenu-pango
|
||||
*/
|
||||
#define PANGO_PATCH 0
|
||||
|
||||
/* With this patch dmenu will not directly display the keyboard input, but instead replace
|
||||
* it with dots. All data from stdin will be ignored.
|
||||
* https://tools.suckless.org/dmenu/patches/password/
|
||||
*/
|
||||
#define PASSWORD_PATCH 0
|
||||
|
||||
/* This patch allows the selected text to be piped back out with dmenu. This can be useful if you
|
||||
* want to display the output of a command on the screen.
|
||||
* Only text starting with the character '#' is piped out by default.
|
||||
*
|
||||
* This patch is not compatible with the json and multi-select patches, both of which takes
|
||||
* precedence over this one.
|
||||
*
|
||||
* https://tools.suckless.org/dmenu/patches/pipeout/
|
||||
*/
|
||||
#define PIPEOUT_PATCH 0
|
||||
|
||||
/* Lifted from the listfullwidth patch this simple change just avoids colors for the prompt (with
|
||||
* the -p option or in config.h) by making it use the same style as the rest of the input field.
|
||||
* The rest of the listfullwidth patch is covered by the vertfull patch.
|
||||
* https://tools.suckless.org/dmenu/patches/listfullwidth/
|
||||
*/
|
||||
#define PLAIN_PROMPT_PATCH 0
|
||||
|
||||
/* This patch changes the behaviour of matched items and the Tab key to allow tab completion.
|
||||
* https://tools.suckless.org/dmenu/patches/prefix-completion/
|
||||
*/
|
||||
#define PREFIXCOMPLETION_PATCH 0
|
||||
|
||||
/* This patch adds an option -ps to specify an item by providing the index that should be
|
||||
* pre-selected.
|
||||
* https://tools.suckless.org/dmenu/patches/preselect/
|
||||
*/
|
||||
#define PRESELECT_PATCH 0
|
||||
|
||||
/* This patch allows dmenu to print out the 0-based index of matched text instead of the matched
|
||||
* text itself. This can be useful in cases where you would like to select entries from one array
|
||||
* of text but index into another, or when you are selecting from an ordered list of non-unique
|
||||
* items.
|
||||
* https://tools.suckless.org/dmenu/patches/printindex/
|
||||
*/
|
||||
#define PRINTINDEX_PATCH 0
|
||||
|
||||
/* This patch adds a flag (-t) which makes Return key to ignore selection and print the input
|
||||
* text to stdout. The flag basically swaps the functions of Return and Shift+Return hotkeys.
|
||||
*
|
||||
* This patch is not compatible with the multi-select and json patches, both of which takes
|
||||
* precedence over this one.
|
||||
*
|
||||
* https://tools.suckless.org/dmenu/patches/printinputtext/
|
||||
*/
|
||||
#define PRINTINPUTTEXT_PATCH 0
|
||||
|
||||
/* This patch adds a new flag to dmenu with which text input will be rejected if it would
|
||||
* result in no matching item.
|
||||
* https://tools.suckless.org/dmenu/patches/reject-no-match/
|
||||
*/
|
||||
#define REJECTNOMATCH_PATCH 0
|
||||
|
||||
/* The input width used to be relative to the input options prior to commit e1e1de7:
|
||||
* https://git.suckless.org/dmenu/commit/e1e1de7b3b8399cba90ddca9613f837b2dbef7b9.html
|
||||
*
|
||||
* This had a performance hit when using large data sets and was removed in favour of having the
|
||||
* input width take up 1/3rd of the available space.
|
||||
*
|
||||
* This option adds that feature back in with some performance optimisations at the cost of
|
||||
* accuracy and correctness.
|
||||
*/
|
||||
#define RELATIVE_INPUT_WIDTH_PATCH 0
|
||||
|
||||
/* This patch adds a '-1' option which disables Shift-Return and Ctrl-Return.
|
||||
* This guarantees that dmenu will only output one item, and that item was read from stdin.
|
||||
* The original patch used '-r'. This was changed to '-1' to avoid conflict with the incremental
|
||||
* patch.
|
||||
* https://tools.suckless.org/dmenu/patches/restrict-return/
|
||||
*/
|
||||
#define RESTRICT_RETURN_PATCH 0
|
||||
|
||||
/* This patch adds support for text scrolling and no longer appends '...' for long input as
|
||||
* it can handle long text.
|
||||
* https://tools.suckless.org/dmenu/patches/scroll/
|
||||
*/
|
||||
#define SCROLL_PATCH 1
|
||||
|
||||
/* This patch adds -d and -D flags which separates the input into two halves; one half to be
|
||||
* displayed in dmenu and the other to be printed to stdout. This patch takes precedence over
|
||||
* the TSV patch.
|
||||
* https://tools.suckless.org/dmenu/patches/separator/
|
||||
*/
|
||||
#define SEPARATOR_PATCH 0
|
||||
|
||||
/* This patch allows the symbols, which are printed in dmenu to indicate that either the input
|
||||
* is too long or there are too many options to be shown in dmenu in one line, to be defined.
|
||||
* https://tools.suckless.org/dmenu/patches/symbols/
|
||||
*/
|
||||
#define SYMBOLS_PATCH 0
|
||||
|
||||
/* With this patch dmenu will split input lines at first tab character and only display first
|
||||
* part, but it will perform matching on and output full lines as usual.
|
||||
*
|
||||
* This can be useful if you want to separate data and representation, for example, a music
|
||||
* player wrapper can display only a track title to user, but still supply full filename to
|
||||
* the underlying script.
|
||||
* https://tools.suckless.org/dmenu/patches/tsv/
|
||||
*/
|
||||
#define TSV_PATCH 0
|
||||
|
||||
/* This patch prevents dmenu from indenting items at the same level as the prompt length.
|
||||
* https://tools.suckless.org/dmenu/patches/vertfull/
|
||||
*/
|
||||
#define VERTFULL_PATCH 0
|
||||
|
||||
/* Adds extended window manager hints such as _NET_WM_WINDOW_TYPE and _NET_WM_WINDOW_TYPE_DOCK.
|
||||
* https://github.com/Baitinq/dmenu/blob/master/patches/dmenu-wm_type.diff
|
||||
*/
|
||||
#define WMTYPE_PATCH 0
|
||||
|
||||
/* This patch adds the ability to configure dmenu via Xresources. At startup, dmenu will read and
|
||||
* apply the resources named below:
|
||||
* dmenu.font : font or font set
|
||||
* dmenu.background : normal background color
|
||||
* dmenu.foreground : normal foreground color
|
||||
* dmenu.selbackground : selected background color
|
||||
* dmenu.selforeground : selected foreground color
|
||||
*
|
||||
* See patch/xresources.c for more color settings.
|
||||
*
|
||||
* https://tools.suckless.org/dmenu/patches/xresources/
|
||||
*/
|
||||
#define XRESOURCES_PATCH 1
|
||||
|
||||
/* This patch adds options for specifying dmenu window position and width.
|
||||
* The center patch takes precedence over the XYW patch if enabled.
|
||||
* https://tools.suckless.org/dmenu/patches/xyw/
|
||||
*/
|
||||
#define XYW_PATCH 0
|
|
@ -6,18 +6,9 @@
|
|||
|
||||
#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, ...) {
|
||||
die(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
@ -33,3 +24,13 @@ die(const char *fmt, ...) {
|
|||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void *
|
||||
ecalloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (!(p = calloc(nmemb, size)))
|
||||
die("calloc:");
|
||||
return p;
|
||||
}
|
|
@ -1,7 +1,11 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(A, B) ((A) > (B) ? (A) : (B))
|
||||
#endif
|
||||
#ifndef MIN
|
||||
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
||||
#endif
|
||||
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
|
||||
|
||||
void die(const char *fmt, ...);
|
|
@ -1,34 +0,0 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
/* Default settings; can be overriden by command line. */
|
||||
|
||||
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
|
||||
/* -fn option overrides fonts[0]; default X11 font or font set */
|
||||
static const char *fonts[] = {
|
||||
"Hack Nerd Font:size=11:"
|
||||
};
|
||||
static const char *prompt = NULL; /* -p option; prompt to the left of input field */
|
||||
|
||||
static const unsigned int baralpha = 0xd0;
|
||||
static const unsigned int borderalpha = OPAQUE;
|
||||
static const unsigned int alphas[][3] = {
|
||||
/* fg bg border */
|
||||
[SchemeNorm] = { OPAQUE, baralpha, borderalpha },
|
||||
[SchemeSel] = { OPAQUE, baralpha, borderalpha },
|
||||
};
|
||||
|
||||
static const char *colors[SchemeLast][2] = {
|
||||
/* fg bg */
|
||||
[SchemeNorm] = { "#bbbbbb", "#222222" },
|
||||
[SchemeSel] = { "#eeeeee", "#005577" },
|
||||
[SchemeOut] = { "#000000", "#00ffff" },
|
||||
[SchemeMid] = { "#eeeeee", "#770000" },
|
||||
};
|
||||
/* -l and -g options; controls number of lines and columns in grid if > 0 */
|
||||
static unsigned int lines = 0;
|
||||
static unsigned int columns = 0;
|
||||
|
||||
/*
|
||||
* Characters not considered part of a word while deleting words
|
||||
* for example: " /?\"&[]"
|
||||
*/
|
||||
static const char worddelimiters[] = " ";
|
847
dmenu/dmenu.c
847
dmenu/dmenu.c
|
@ -1,847 +0,0 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
#include <ctype.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xutil.h>
|
||||
#ifdef XINERAMA
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
#endif
|
||||
#include <X11/Xft/Xft.h>
|
||||
|
||||
#include "drw.h"
|
||||
#include "util.h"
|
||||
|
||||
/* macros */
|
||||
#define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \
|
||||
* MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org)))
|
||||
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
||||
#define OPAQUE 0xffU
|
||||
|
||||
/* enums */
|
||||
enum { SchemeNorm, SchemeSel, SchemeOut, SchemeMid, SchemeLast }; /* color schemes */
|
||||
|
||||
struct item {
|
||||
char *text;
|
||||
struct item *left, *right;
|
||||
int out;
|
||||
};
|
||||
|
||||
static char text[BUFSIZ] = "";
|
||||
static char *embed;
|
||||
static int bh, mw, mh;
|
||||
static int inputw = 0, promptw;
|
||||
static int lrpad; /* sum of left and right padding */
|
||||
static size_t cursor;
|
||||
static struct item *items = NULL;
|
||||
static struct item *matches, *matchend;
|
||||
static struct item *prev, *curr, *next, *sel;
|
||||
static int mon = -1, screen;
|
||||
|
||||
static Atom clip, utf8;
|
||||
static Display *dpy;
|
||||
static Window root, parentwin, win;
|
||||
static XIC xic;
|
||||
|
||||
static int useargb = 0;
|
||||
static Visual *visual;
|
||||
static int depth;
|
||||
static Colormap cmap;
|
||||
|
||||
static Drw *drw;
|
||||
static Clr *scheme[SchemeLast];
|
||||
|
||||
#include "config.h"
|
||||
|
||||
static char * cistrstr(const char *s, const char *sub);
|
||||
static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp;
|
||||
static char *(*fstrstr)(const char *, const char *) = cistrstr;
|
||||
|
||||
static void
|
||||
appenditem(struct item *item, struct item **list, struct item **last)
|
||||
{
|
||||
if (*last)
|
||||
(*last)->right = item;
|
||||
else
|
||||
*list = item;
|
||||
|
||||
item->left = *last;
|
||||
item->right = NULL;
|
||||
*last = item;
|
||||
}
|
||||
|
||||
static void
|
||||
calcoffsets(void)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
if (lines > 0)
|
||||
n = lines * columns * bh;
|
||||
else
|
||||
n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
|
||||
/* calculate which items will begin the next page and previous page */
|
||||
for (i = 0, next = curr; next; next = next->right)
|
||||
if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n)
|
||||
break;
|
||||
for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
|
||||
if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n)
|
||||
break;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
XUngrabKey(dpy, AnyKey, AnyModifier, root);
|
||||
for (i = 0; i < SchemeLast; i++)
|
||||
free(scheme[i]);
|
||||
drw_free(drw);
|
||||
XSync(dpy, False);
|
||||
XCloseDisplay(dpy);
|
||||
}
|
||||
|
||||
static char *
|
||||
cistrstr(const char *h, const char *n)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!n[0])
|
||||
return (char *)h;
|
||||
|
||||
for (; *h; ++h) {
|
||||
for (i = 0; n[i] && tolower((unsigned char)n[i]) ==
|
||||
tolower((unsigned char)h[i]); ++i)
|
||||
;
|
||||
if (n[i] == '\0')
|
||||
return (char *)h;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
drawitem(struct item *item, int x, int y, int w)
|
||||
{
|
||||
if (item == sel)
|
||||
drw_setscheme(drw, scheme[SchemeSel]);
|
||||
else if (item->left == sel || item->right == sel)
|
||||
drw_setscheme(drw, scheme[SchemeMid]);
|
||||
else if (item->out)
|
||||
drw_setscheme(drw, scheme[SchemeOut]);
|
||||
else
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
|
||||
return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
drawmenu(void)
|
||||
{
|
||||
unsigned int curpos;
|
||||
struct item *item;
|
||||
int x = 0, y = 0, w;
|
||||
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
drw_rect(drw, 0, 0, mw, mh, 1, 1);
|
||||
|
||||
if (prompt && *prompt) {
|
||||
drw_setscheme(drw, scheme[SchemeSel]);
|
||||
x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0);
|
||||
}
|
||||
/* draw input field */
|
||||
w = (lines > 0 || !matches) ? mw - x : inputw;
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
|
||||
|
||||
curpos = TEXTW(text) - TEXTW(&text[cursor]);
|
||||
if ((curpos += lrpad / 2 - 1) < w) {
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
|
||||
}
|
||||
|
||||
if (lines > 0) {
|
||||
/* draw grid */
|
||||
int i = 0;
|
||||
for (item = curr; item != next; item = item->right, i++)
|
||||
drawitem(
|
||||
item,
|
||||
x + ((i / lines) * ((mw - x) / columns)),
|
||||
y + (((i % lines) + 1) * bh),
|
||||
(mw - x) / columns
|
||||
);
|
||||
} else if (matches) {
|
||||
/* draw horizontal list */
|
||||
x += inputw;
|
||||
w = TEXTW("<");
|
||||
if (curr->left) {
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
drw_text(drw, x, 0, w, bh, lrpad / 2, "<", 0);
|
||||
}
|
||||
x += w;
|
||||
for (item = curr; item != next; item = item->right)
|
||||
x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">")));
|
||||
if (next) {
|
||||
w = TEXTW(">");
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
drw_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0);
|
||||
}
|
||||
}
|
||||
drw_map(drw, win, 0, 0, mw, mh);
|
||||
}
|
||||
|
||||
static void
|
||||
grabfocus(void)
|
||||
{
|
||||
struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 };
|
||||
Window focuswin;
|
||||
int i, revertwin;
|
||||
|
||||
for (i = 0; i < 100; ++i) {
|
||||
XGetInputFocus(dpy, &focuswin, &revertwin);
|
||||
if (focuswin == win)
|
||||
return;
|
||||
XSetInputFocus(dpy, win, RevertToParent, CurrentTime);
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
die("cannot grab focus");
|
||||
}
|
||||
|
||||
static void
|
||||
grabkeyboard(void)
|
||||
{
|
||||
struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
|
||||
int i;
|
||||
|
||||
if (embed)
|
||||
return;
|
||||
/* try to grab keyboard, we may have to wait for another process to ungrab */
|
||||
for (i = 0; i < 1000; i++) {
|
||||
if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync,
|
||||
GrabModeAsync, CurrentTime) == GrabSuccess)
|
||||
return;
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
die("cannot grab keyboard");
|
||||
}
|
||||
|
||||
static void
|
||||
match(void)
|
||||
{
|
||||
static char **tokv = NULL;
|
||||
static int tokn = 0;
|
||||
|
||||
char buf[sizeof text], *s;
|
||||
int i, tokc = 0;
|
||||
size_t len, textsize;
|
||||
struct item *item, *lprefix, *lsubstr, *prefixend, *substrend;
|
||||
|
||||
strcpy(buf, text);
|
||||
/* separate input text into tokens to be matched individually */
|
||||
for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " "))
|
||||
if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))
|
||||
die("cannot realloc %u bytes:", tokn * sizeof *tokv);
|
||||
len = tokc ? strlen(tokv[0]) : 0;
|
||||
|
||||
matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
|
||||
textsize = strlen(text) + 1;
|
||||
for (item = items; item && item->text; item++) {
|
||||
for (i = 0; i < tokc; i++)
|
||||
if (!fstrstr(item->text, tokv[i]))
|
||||
break;
|
||||
if (i != tokc) /* not all tokens match */
|
||||
continue;
|
||||
/* exact matches go first, then prefixes, then substrings */
|
||||
if (!tokc || !fstrncmp(text, item->text, textsize))
|
||||
appenditem(item, &matches, &matchend);
|
||||
else if (!fstrncmp(tokv[0], item->text, len))
|
||||
appenditem(item, &lprefix, &prefixend);
|
||||
else
|
||||
appenditem(item, &lsubstr, &substrend);
|
||||
}
|
||||
if (lprefix) {
|
||||
if (matches) {
|
||||
matchend->right = lprefix;
|
||||
lprefix->left = matchend;
|
||||
} else
|
||||
matches = lprefix;
|
||||
matchend = prefixend;
|
||||
}
|
||||
if (lsubstr) {
|
||||
if (matches) {
|
||||
matchend->right = lsubstr;
|
||||
lsubstr->left = matchend;
|
||||
} else
|
||||
matches = lsubstr;
|
||||
matchend = substrend;
|
||||
}
|
||||
curr = sel = matches;
|
||||
calcoffsets();
|
||||
}
|
||||
|
||||
static void
|
||||
insert(const char *str, ssize_t n)
|
||||
{
|
||||
if (strlen(text) + n > sizeof text - 1)
|
||||
return;
|
||||
/* move existing text out of the way, insert new text, and update cursor */
|
||||
memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0));
|
||||
if (n > 0)
|
||||
memcpy(&text[cursor], str, n);
|
||||
cursor += n;
|
||||
match();
|
||||
}
|
||||
|
||||
static size_t
|
||||
nextrune(int inc)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
/* return location of next utf8 rune in the given direction (+1 or -1) */
|
||||
for (n = cursor + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc)
|
||||
;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void
|
||||
movewordedge(int dir)
|
||||
{
|
||||
if (dir < 0) { /* move cursor to the start of the word*/
|
||||
while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
|
||||
cursor = nextrune(-1);
|
||||
while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
|
||||
cursor = nextrune(-1);
|
||||
} else { /* move cursor to the end of the word */
|
||||
while (text[cursor] && strchr(worddelimiters, text[cursor]))
|
||||
cursor = nextrune(+1);
|
||||
while (text[cursor] && !strchr(worddelimiters, text[cursor]))
|
||||
cursor = nextrune(+1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
keypress(XKeyEvent *ev)
|
||||
{
|
||||
char buf[32];
|
||||
int len;
|
||||
KeySym ksym;
|
||||
Status status;
|
||||
|
||||
len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status);
|
||||
switch (status) {
|
||||
default: /* XLookupNone, XBufferOverflow */
|
||||
return;
|
||||
case XLookupChars:
|
||||
goto insert;
|
||||
case XLookupKeySym:
|
||||
case XLookupBoth:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ev->state & ControlMask) {
|
||||
switch(ksym) {
|
||||
case XK_a: ksym = XK_Home; break;
|
||||
case XK_b: ksym = XK_Left; break;
|
||||
case XK_c: ksym = XK_Escape; break;
|
||||
case XK_d: ksym = XK_Delete; break;
|
||||
case XK_e: ksym = XK_End; break;
|
||||
case XK_f: ksym = XK_Right; break;
|
||||
case XK_g: ksym = XK_Escape; break;
|
||||
case XK_h: ksym = XK_BackSpace; break;
|
||||
case XK_i: ksym = XK_Tab; break;
|
||||
case XK_j: /* fallthrough */
|
||||
case XK_J: /* fallthrough */
|
||||
case XK_m: /* fallthrough */
|
||||
case XK_M: ksym = XK_Return; ev->state &= ~ControlMask; break;
|
||||
case XK_n: ksym = XK_Down; break;
|
||||
case XK_p: ksym = XK_Up; break;
|
||||
|
||||
case XK_k: /* delete right */
|
||||
text[cursor] = '\0';
|
||||
match();
|
||||
break;
|
||||
case XK_u: /* delete left */
|
||||
insert(NULL, 0 - cursor);
|
||||
break;
|
||||
case XK_w: /* delete word */
|
||||
while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
|
||||
insert(NULL, nextrune(-1) - cursor);
|
||||
while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
|
||||
insert(NULL, nextrune(-1) - cursor);
|
||||
break;
|
||||
case XK_y: /* paste selection */
|
||||
case XK_Y:
|
||||
XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
|
||||
utf8, utf8, win, CurrentTime);
|
||||
return;
|
||||
case XK_Left:
|
||||
case XK_KP_Left:
|
||||
movewordedge(-1);
|
||||
goto draw;
|
||||
case XK_Right:
|
||||
case XK_KP_Right:
|
||||
movewordedge(+1);
|
||||
goto draw;
|
||||
case XK_Return:
|
||||
case XK_KP_Enter:
|
||||
break;
|
||||
case XK_bracketleft:
|
||||
cleanup();
|
||||
exit(1);
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} else if (ev->state & Mod1Mask) {
|
||||
switch(ksym) {
|
||||
case XK_b:
|
||||
movewordedge(-1);
|
||||
goto draw;
|
||||
case XK_f:
|
||||
movewordedge(+1);
|
||||
goto draw;
|
||||
case XK_g: ksym = XK_Home; break;
|
||||
case XK_G: ksym = XK_End; break;
|
||||
case XK_h: ksym = XK_Up; break;
|
||||
case XK_j: ksym = XK_Next; break;
|
||||
case XK_k: ksym = XK_Prior; break;
|
||||
case XK_l: ksym = XK_Down; break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch(ksym) {
|
||||
default:
|
||||
insert:
|
||||
if (!iscntrl(*buf))
|
||||
insert(buf, len);
|
||||
break;
|
||||
case XK_Delete:
|
||||
case XK_KP_Delete:
|
||||
if (text[cursor] == '\0')
|
||||
return;
|
||||
cursor = nextrune(+1);
|
||||
/* fallthrough */
|
||||
case XK_BackSpace:
|
||||
if (cursor == 0)
|
||||
return;
|
||||
insert(NULL, nextrune(-1) - cursor);
|
||||
break;
|
||||
case XK_End:
|
||||
case XK_KP_End:
|
||||
if (text[cursor] != '\0') {
|
||||
cursor = strlen(text);
|
||||
break;
|
||||
}
|
||||
if (next) {
|
||||
/* jump to end of list and position items in reverse */
|
||||
curr = matchend;
|
||||
calcoffsets();
|
||||
curr = prev;
|
||||
calcoffsets();
|
||||
while (next && (curr = curr->right))
|
||||
calcoffsets();
|
||||
}
|
||||
sel = matchend;
|
||||
break;
|
||||
case XK_Escape:
|
||||
cleanup();
|
||||
exit(1);
|
||||
case XK_Home:
|
||||
case XK_KP_Home:
|
||||
if (sel == matches) {
|
||||
cursor = 0;
|
||||
break;
|
||||
}
|
||||
sel = curr = matches;
|
||||
calcoffsets();
|
||||
break;
|
||||
case XK_Left:
|
||||
case XK_KP_Left:
|
||||
if (cursor > 0 && (!sel || !sel->left || lines > 0)) {
|
||||
cursor = nextrune(-1);
|
||||
break;
|
||||
}
|
||||
if (lines > 0)
|
||||
return;
|
||||
/* fallthrough */
|
||||
case XK_Up:
|
||||
case XK_KP_Up:
|
||||
if (sel && sel->left && (sel = sel->left)->right == curr) {
|
||||
curr = prev;
|
||||
calcoffsets();
|
||||
}
|
||||
break;
|
||||
case XK_Next:
|
||||
case XK_KP_Next:
|
||||
if (!next)
|
||||
return;
|
||||
sel = curr = next;
|
||||
calcoffsets();
|
||||
break;
|
||||
case XK_Prior:
|
||||
case XK_KP_Prior:
|
||||
if (!prev)
|
||||
return;
|
||||
sel = curr = prev;
|
||||
calcoffsets();
|
||||
break;
|
||||
case XK_Return:
|
||||
case XK_KP_Enter:
|
||||
puts((sel && !(ev->state & ShiftMask)) ? sel->text : text);
|
||||
if (!(ev->state & ControlMask)) {
|
||||
cleanup();
|
||||
exit(0);
|
||||
}
|
||||
if (sel)
|
||||
sel->out = 1;
|
||||
break;
|
||||
case XK_Right:
|
||||
case XK_KP_Right:
|
||||
if (text[cursor] != '\0') {
|
||||
cursor = nextrune(+1);
|
||||
break;
|
||||
}
|
||||
if (lines > 0)
|
||||
return;
|
||||
/* fallthrough */
|
||||
case XK_Down:
|
||||
case XK_KP_Down:
|
||||
if (sel && sel->right && (sel = sel->right) == next) {
|
||||
curr = next;
|
||||
calcoffsets();
|
||||
}
|
||||
break;
|
||||
case XK_Tab:
|
||||
if (!sel)
|
||||
return;
|
||||
strncpy(text, sel->text, sizeof text - 1);
|
||||
text[sizeof text - 1] = '\0';
|
||||
cursor = strlen(text);
|
||||
match();
|
||||
break;
|
||||
}
|
||||
|
||||
draw:
|
||||
drawmenu();
|
||||
}
|
||||
|
||||
static void
|
||||
paste(void)
|
||||
{
|
||||
char *p, *q;
|
||||
int di;
|
||||
unsigned long dl;
|
||||
Atom da;
|
||||
|
||||
/* we have been given the current selection, now insert it into input */
|
||||
if (XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False,
|
||||
utf8, &da, &di, &dl, &dl, (unsigned char **)&p)
|
||||
== Success && p) {
|
||||
insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p));
|
||||
XFree(p);
|
||||
}
|
||||
drawmenu();
|
||||
}
|
||||
|
||||
static void
|
||||
xinitvisual()
|
||||
{
|
||||
XVisualInfo *infos;
|
||||
XRenderPictFormat *fmt;
|
||||
int nitems;
|
||||
int i;
|
||||
|
||||
XVisualInfo tpl = {
|
||||
.screen = screen,
|
||||
.depth = 32,
|
||||
.class = TrueColor
|
||||
};
|
||||
long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
|
||||
|
||||
infos = XGetVisualInfo(dpy, masks, &tpl, &nitems);
|
||||
visual = NULL;
|
||||
for(i = 0; i < nitems; i ++) {
|
||||
fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
|
||||
if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
|
||||
visual = infos[i].visual;
|
||||
depth = infos[i].depth;
|
||||
cmap = XCreateColormap(dpy, root, visual, AllocNone);
|
||||
useargb = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XFree(infos);
|
||||
|
||||
if (! visual) {
|
||||
visual = DefaultVisual(dpy, screen);
|
||||
depth = DefaultDepth(dpy, screen);
|
||||
cmap = DefaultColormap(dpy, screen);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
readstdin(void)
|
||||
{
|
||||
char buf[sizeof text], *p;
|
||||
size_t i, imax = 0, size = 0;
|
||||
unsigned int tmpmax = 0;
|
||||
|
||||
/* read each line from stdin and add it to the item list */
|
||||
for (i = 0; fgets(buf, sizeof buf, stdin); i++) {
|
||||
if (i + 1 >= size / sizeof *items)
|
||||
if (!(items = realloc(items, (size += BUFSIZ))))
|
||||
die("cannot realloc %u bytes:", size);
|
||||
if ((p = strchr(buf, '\n')))
|
||||
*p = '\0';
|
||||
if (!(items[i].text = strdup(buf)))
|
||||
die("cannot strdup %u bytes:", strlen(buf) + 1);
|
||||
items[i].out = 0;
|
||||
drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL);
|
||||
if (tmpmax > inputw) {
|
||||
inputw = tmpmax;
|
||||
imax = i;
|
||||
}
|
||||
}
|
||||
if (items)
|
||||
items[i].text = NULL;
|
||||
inputw = items ? TEXTW(items[imax].text) : 0;
|
||||
lines = MIN(lines, i);
|
||||
}
|
||||
|
||||
static void
|
||||
run(void)
|
||||
{
|
||||
XEvent ev;
|
||||
|
||||
while (!XNextEvent(dpy, &ev)) {
|
||||
if (XFilterEvent(&ev, win))
|
||||
continue;
|
||||
switch(ev.type) {
|
||||
case DestroyNotify:
|
||||
if (ev.xdestroywindow.window != win)
|
||||
break;
|
||||
cleanup();
|
||||
exit(1);
|
||||
case Expose:
|
||||
if (ev.xexpose.count == 0)
|
||||
drw_map(drw, win, 0, 0, mw, mh);
|
||||
break;
|
||||
case FocusIn:
|
||||
/* regrab focus from parent window */
|
||||
if (ev.xfocus.window != win)
|
||||
grabfocus();
|
||||
break;
|
||||
case KeyPress:
|
||||
keypress(&ev.xkey);
|
||||
break;
|
||||
case SelectionNotify:
|
||||
if (ev.xselection.property == utf8)
|
||||
paste();
|
||||
break;
|
||||
case VisibilityNotify:
|
||||
if (ev.xvisibility.state != VisibilityUnobscured)
|
||||
XRaiseWindow(dpy, win);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
setup(void)
|
||||
{
|
||||
int x, y, i, j;
|
||||
unsigned int du;
|
||||
XSetWindowAttributes swa;
|
||||
XIM xim;
|
||||
Window w, dw, *dws;
|
||||
XWindowAttributes wa;
|
||||
XClassHint ch = {"dmenu", "dmenu"};
|
||||
#ifdef XINERAMA
|
||||
XineramaScreenInfo *info;
|
||||
Window pw;
|
||||
int a, di, n, area = 0;
|
||||
#endif
|
||||
/* init appearance */
|
||||
for (j = 0; j < SchemeLast; j++)
|
||||
scheme[j] = drw_scm_create(drw, colors[j], alphas[j], 2);
|
||||
|
||||
clip = XInternAtom(dpy, "CLIPBOARD", False);
|
||||
utf8 = XInternAtom(dpy, "UTF8_STRING", False);
|
||||
|
||||
/* calculate menu geometry */
|
||||
bh = drw->fonts->h + 2;
|
||||
lines = MAX(lines, 0);
|
||||
mh = (lines + 1) * bh;
|
||||
#ifdef XINERAMA
|
||||
i = 0;
|
||||
if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
|
||||
XGetInputFocus(dpy, &w, &di);
|
||||
if (mon >= 0 && mon < n)
|
||||
i = mon;
|
||||
else if (w != root && w != PointerRoot && w != None) {
|
||||
/* find top-level window containing current input focus */
|
||||
do {
|
||||
if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws)
|
||||
XFree(dws);
|
||||
} while (w != root && w != pw);
|
||||
/* find xinerama screen with which the window intersects most */
|
||||
if (XGetWindowAttributes(dpy, pw, &wa))
|
||||
for (j = 0; j < n; j++)
|
||||
if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) {
|
||||
area = a;
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
/* no focused window is on screen, so use pointer location instead */
|
||||
if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du))
|
||||
for (i = 0; i < n; i++)
|
||||
if (INTERSECT(x, y, 1, 1, info[i]) != 0)
|
||||
break;
|
||||
|
||||
x = info[i].x_org;
|
||||
y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
|
||||
mw = info[i].width;
|
||||
XFree(info);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (!XGetWindowAttributes(dpy, parentwin, &wa))
|
||||
die("could not get embedding window attributes: 0x%lx",
|
||||
parentwin);
|
||||
x = 0;
|
||||
y = topbar ? 0 : wa.height - mh;
|
||||
mw = wa.width;
|
||||
}
|
||||
promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
|
||||
inputw = MIN(inputw, mw/3);
|
||||
match();
|
||||
|
||||
/* create menu window */
|
||||
swa.override_redirect = True;
|
||||
swa.background_pixel = 0;
|
||||
swa.colormap = cmap;
|
||||
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
|
||||
win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
|
||||
depth, InputOutput, visual,
|
||||
CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &swa);
|
||||
XSetClassHint(dpy, win, &ch);
|
||||
|
||||
|
||||
/* input methods */
|
||||
if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL)
|
||||
die("XOpenIM failed: could not open input device");
|
||||
|
||||
xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
|
||||
XNClientWindow, win, XNFocusWindow, win, NULL);
|
||||
|
||||
XMapRaised(dpy, win);
|
||||
if (embed) {
|
||||
XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask);
|
||||
if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) {
|
||||
for (i = 0; i < du && dws[i] != win; ++i)
|
||||
XSelectInput(dpy, dws[i], FocusChangeMask);
|
||||
XFree(dws);
|
||||
}
|
||||
grabfocus();
|
||||
}
|
||||
drw_resize(drw, mw, mh);
|
||||
drawmenu();
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
|
||||
" [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
XWindowAttributes wa;
|
||||
int i, fast = 0;
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
/* these options take no arguments */
|
||||
if (!strcmp(argv[i], "-v")) { /* prints version information */
|
||||
puts("dmenu-"VERSION);
|
||||
exit(0);
|
||||
} else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */
|
||||
topbar = 0;
|
||||
else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */
|
||||
fast = 1;
|
||||
else if (!strcmp(argv[i], "-s")) { /* case-sensitive item matching */
|
||||
fstrncmp = strncmp;
|
||||
fstrstr = strstr;
|
||||
} else if (i + 1 == argc)
|
||||
usage();
|
||||
/* these options take one argument */
|
||||
else if (!strcmp(argv[i], "-g")) { /* number of columns in grid */
|
||||
columns = atoi(argv[++i]);
|
||||
if (lines == 0) lines = 1;
|
||||
} else if (!strcmp(argv[i], "-l")) { /* number of lines in grid */
|
||||
lines = atoi(argv[++i]);
|
||||
if (columns == 0) columns = 1;
|
||||
} else if (!strcmp(argv[i], "-m"))
|
||||
mon = atoi(argv[++i]);
|
||||
else if (!strcmp(argv[i], "-p")) /* adds prompt to left of input field */
|
||||
prompt = argv[++i];
|
||||
else if (!strcmp(argv[i], "-fn")) /* font or font set */
|
||||
fonts[0] = argv[++i];
|
||||
else if (!strcmp(argv[i], "-nb")) /* normal background color */
|
||||
colors[SchemeNorm][ColBg] = argv[++i];
|
||||
else if (!strcmp(argv[i], "-nf")) /* normal foreground color */
|
||||
colors[SchemeNorm][ColFg] = argv[++i];
|
||||
else if (!strcmp(argv[i], "-sb")) /* selected background color */
|
||||
colors[SchemeSel][ColBg] = argv[++i];
|
||||
else if (!strcmp(argv[i], "-sf")) /* selected foreground color */
|
||||
colors[SchemeSel][ColFg] = argv[++i];
|
||||
else if (!strcmp(argv[i], "-w")) /* embedding window id */
|
||||
embed = argv[++i];
|
||||
else
|
||||
usage();
|
||||
|
||||
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
|
||||
fputs("warning: no locale support\n", stderr);
|
||||
if (!(dpy = XOpenDisplay(NULL)))
|
||||
die("cannot open display");
|
||||
screen = DefaultScreen(dpy);
|
||||
root = RootWindow(dpy, screen);
|
||||
if (!embed || !(parentwin = strtol(embed, NULL, 0)))
|
||||
parentwin = root;
|
||||
if (!XGetWindowAttributes(dpy, parentwin, &wa))
|
||||
die("could not get embedding window attributes: 0x%lx",
|
||||
parentwin);
|
||||
xinitvisual();
|
||||
drw = drw_create(dpy, screen, root, wa.width, wa.height, visual, depth, cmap);
|
||||
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
|
||||
die("no fonts could be loaded.");
|
||||
lrpad = drw->fonts->h;
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
if (pledge("stdio rpath", NULL) == -1)
|
||||
die("pledge");
|
||||
#endif
|
||||
|
||||
if (fast && !isatty(0)) {
|
||||
grabkeyboard();
|
||||
readstdin();
|
||||
} else {
|
||||
readstdin();
|
||||
grabkeyboard();
|
||||
}
|
||||
setup();
|
||||
run();
|
||||
|
||||
return 1; /* unreachable */
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
#!/bin/sh
|
||||
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &
|
|
@ -1,281 +0,0 @@
|
|||
From 5e232dc79ba3c0b791f3d9ddfab2fcecca19f18d Mon Sep 17 00:00:00 2001
|
||||
From: bakkeby <bakkeby@gmail.com>
|
||||
Date: Thu, 28 May 2020 16:58:12 +0200
|
||||
Subject: [PATCH] Adding alpha patch
|
||||
|
||||
---
|
||||
config.def.h | 9 +++++++++
|
||||
config.mk | 6 +++++-
|
||||
dmenu.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++------
|
||||
drw.c | 26 +++++++++++++-----------
|
||||
drw.h | 9 ++++++---
|
||||
5 files changed, 84 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 1edb647..5c512d3 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -7,6 +7,15 @@ static const char *fonts[] = {
|
||||
"monospace:size=10"
|
||||
};
|
||||
static const char *prompt = NULL; /* -p option; prompt to the left of input field */
|
||||
+
|
||||
+static const unsigned int baralpha = 0xd0;
|
||||
+static const unsigned int borderalpha = OPAQUE;
|
||||
+static const unsigned int alphas[][3] = {
|
||||
+ /* fg bg border */
|
||||
+ [SchemeNorm] = { OPAQUE, baralpha, borderalpha },
|
||||
+ [SchemeSel] = { OPAQUE, baralpha, borderalpha },
|
||||
+};
|
||||
+
|
||||
static const char *colors[SchemeLast][2] = {
|
||||
/* fg bg */
|
||||
[SchemeNorm] = { "#bbbbbb", "#222222" },
|
||||
diff --git a/config.mk b/config.mk
|
||||
index 05d5a3e..ee4991a 100644
|
||||
--- a/config.mk
|
||||
+++ b/config.mk
|
||||
@@ -15,12 +15,16 @@ XINERAMAFLAGS = -DXINERAMA
|
||||
# freetype
|
||||
FREETYPELIBS = -lfontconfig -lXft
|
||||
FREETYPEINC = /usr/include/freetype2
|
||||
+
|
||||
+# alpha
|
||||
+XRENDERLIBS = -lXrender
|
||||
+
|
||||
# OpenBSD (uncomment)
|
||||
#FREETYPEINC = $(X11INC)/freetype2
|
||||
|
||||
# includes and libs
|
||||
INCS = -I$(X11INC) -I$(FREETYPEINC)
|
||||
-LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)
|
||||
+LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) ${XRENDERLIBS}
|
||||
|
||||
# flags
|
||||
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS)
|
||||
diff --git a/dmenu.c b/dmenu.c
|
||||
index 65f25ce..31efafc 100644
|
||||
--- a/dmenu.c
|
||||
+++ b/dmenu.c
|
||||
@@ -24,6 +24,7 @@
|
||||
* MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org)))
|
||||
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
||||
+#define OPAQUE 0xffU
|
||||
|
||||
/* enums */
|
||||
enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
|
||||
@@ -50,6 +51,11 @@ static Display *dpy;
|
||||
static Window root, parentwin, win;
|
||||
static XIC xic;
|
||||
|
||||
+static int useargb = 0;
|
||||
+static Visual *visual;
|
||||
+static int depth;
|
||||
+static Colormap cmap;
|
||||
+
|
||||
static Drw *drw;
|
||||
static Clr *scheme[SchemeLast];
|
||||
|
||||
@@ -518,6 +524,43 @@ paste(void)
|
||||
drawmenu();
|
||||
}
|
||||
|
||||
+static void
|
||||
+xinitvisual()
|
||||
+{
|
||||
+ XVisualInfo *infos;
|
||||
+ XRenderPictFormat *fmt;
|
||||
+ int nitems;
|
||||
+ int i;
|
||||
+
|
||||
+ XVisualInfo tpl = {
|
||||
+ .screen = screen,
|
||||
+ .depth = 32,
|
||||
+ .class = TrueColor
|
||||
+ };
|
||||
+ long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
|
||||
+
|
||||
+ infos = XGetVisualInfo(dpy, masks, &tpl, &nitems);
|
||||
+ visual = NULL;
|
||||
+ for(i = 0; i < nitems; i ++) {
|
||||
+ fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
|
||||
+ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
|
||||
+ visual = infos[i].visual;
|
||||
+ depth = infos[i].depth;
|
||||
+ cmap = XCreateColormap(dpy, root, visual, AllocNone);
|
||||
+ useargb = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ XFree(infos);
|
||||
+
|
||||
+ if (! visual) {
|
||||
+ visual = DefaultVisual(dpy, screen);
|
||||
+ depth = DefaultDepth(dpy, screen);
|
||||
+ cmap = DefaultColormap(dpy, screen);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void
|
||||
readstdin(void)
|
||||
{
|
||||
@@ -602,7 +645,7 @@ setup(void)
|
||||
#endif
|
||||
/* init appearance */
|
||||
for (j = 0; j < SchemeLast; j++)
|
||||
- scheme[j] = drw_scm_create(drw, colors[j], 2);
|
||||
+ scheme[j] = drw_scm_create(drw, colors[j], alphas[j], 2);
|
||||
|
||||
clip = XInternAtom(dpy, "CLIPBOARD", False);
|
||||
utf8 = XInternAtom(dpy, "UTF8_STRING", False);
|
||||
@@ -657,14 +700,14 @@ setup(void)
|
||||
|
||||
/* create menu window */
|
||||
swa.override_redirect = True;
|
||||
- swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
||||
+ swa.background_pixel = 0;
|
||||
+ swa.colormap = cmap;
|
||||
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
|
||||
win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
|
||||
- CopyFromParent, CopyFromParent, CopyFomParent,
|
||||
- CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
|
||||
+ depth, InputOutput, visual,
|
||||
+ CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &swa);
|
||||
XSetClassHint(dpy, win, &ch);
|
||||
|
||||
-
|
||||
/* input methods */
|
||||
if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL)
|
||||
die("XOpenIM failed: could not open input device");
|
||||
@@ -747,7 +790,8 @@ main(int argc, char *argv[])
|
||||
if (!XGetWindowAttributes(dpy, parentwin, &wa))
|
||||
die("could not get embedding window attributes: 0x%lx",
|
||||
parentwin);
|
||||
- drw = drw_create(dpy, screen, root, wa.width, wa.height);
|
||||
+ xinitvisual();
|
||||
+ drw = drw_create(dpy, screen, root, wa.width, wa.height, visual, depth, cmap);
|
||||
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
|
||||
die("no fonts could be loaded.");
|
||||
lrpad = drw->fonts->h;
|
||||
diff --git a/drw.c b/drw.c
|
||||
index 4cdbcbe..fe3aadd 100644
|
||||
--- a/drw.c
|
||||
+++ b/drw.c
|
||||
@@ -61,7 +61,7 @@ utf8decode(const char *c, long *u, size_t clen)
|
||||
}
|
||||
|
||||
Drw *
|
||||
-drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
|
||||
+drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
|
||||
{
|
||||
Drw *drw = ecalloc(1, sizeof(Drw));
|
||||
|
||||
@@ -70,8 +70,11 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
|
||||
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);
|
||||
+ drw->visual = visual;
|
||||
+ drw->depth = depth;
|
||||
+ drw->cmap = cmap;
|
||||
+ drw->drawable = XCreatePixmap(dpy, root, w, h, depth);
|
||||
+ drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
|
||||
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
|
||||
|
||||
return drw;
|
||||
@@ -87,7 +90,7 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h)
|
||||
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));
|
||||
+ drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -194,21 +197,22 @@ drw_fontset_free(Fnt *font)
|
||||
}
|
||||
|
||||
void
|
||||
-drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
|
||||
+drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha)
|
||||
{
|
||||
if (!drw || !dest || !clrname)
|
||||
return;
|
||||
|
||||
- if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
|
||||
- DefaultColormap(drw->dpy, drw->screen),
|
||||
+ if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
|
||||
clrname, dest))
|
||||
die("error, cannot allocate color '%s'", clrname);
|
||||
+
|
||||
+ dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 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)
|
||||
+drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount)
|
||||
{
|
||||
size_t i;
|
||||
Clr *ret;
|
||||
@@ -218,7 +222,7 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < clrcount; i++)
|
||||
- drw_clr_create(drw, &ret[i], clrnames[i]);
|
||||
+ drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -274,9 +278,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
} 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));
|
||||
+ d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
|
||||
x += lpad;
|
||||
w -= lpad;
|
||||
}
|
||||
diff --git a/drw.h b/drw.h
|
||||
index 4c67419..4f66f0d 100644
|
||||
--- a/drw.h
|
||||
+++ b/drw.h
|
||||
@@ -20,6 +20,9 @@ typedef struct {
|
||||
Display *dpy;
|
||||
int screen;
|
||||
Window root;
|
||||
+ Visual *visual;
|
||||
+ unsigned int depth;
|
||||
+ Colormap cmap;
|
||||
Drawable drawable;
|
||||
GC gc;
|
||||
Clr *scheme;
|
||||
@@ -27,7 +30,7 @@ typedef struct {
|
||||
} Drw;
|
||||
|
||||
/* Drawable abstraction */
|
||||
-Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
|
||||
+Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap);
|
||||
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
|
||||
void drw_free(Drw *drw);
|
||||
|
||||
@@ -38,8 +41,8 @@ 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);
|
||||
+void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha);
|
||||
+Clr *drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount);
|
||||
|
||||
/* Cursor abstraction */
|
||||
Cur *drw_cur_create(Drw *drw, int shape);
|
||||
--
|
||||
2.34.1
|
||||
r
|
|
@ -1,42 +0,0 @@
|
|||
From 54acbdf72083a5eae5783eed42e162424ab2cec2 Mon Sep 17 00:00:00 2001
|
||||
From: Kim Torgersen <kim@torgersen.se>
|
||||
Date: Sat, 23 May 2020 14:48:28 +0200
|
||||
Subject: [PATCH] case-insensitive item matching default, case-sensitive option
|
||||
(-s)
|
||||
|
||||
---
|
||||
dmenu.c | 11 ++++++-----
|
||||
1 file changed, 6 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dmenu.c b/dmenu.c
|
||||
index 65f25ce..855df59 100644
|
||||
--- a/dmenu.c
|
||||
+++ b/dmenu.c
|
||||
@@ -55,8 +55,9 @@ static Clr *scheme[SchemeLast];
|
||||
|
||||
#include "config.h"
|
||||
|
||||
-static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
|
||||
-static char *(*fstrstr)(const char *, const char *) = strstr;
|
||||
+static char * cistrstr(const char *s, const char *sub);
|
||||
+static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp;
|
||||
+static char *(*fstrstr)(const char *, const char *) = cistrstr;
|
||||
|
||||
static void
|
||||
appenditem(struct item *item, struct item **list, struct item **last)
|
||||
@@ -709,9 +710,9 @@ main(int argc, char *argv[])
|
||||
topbar = 0;
|
||||
else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */
|
||||
fast = 1;
|
||||
- else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
|
||||
- fstrncmp = strncasecmp;
|
||||
- fstrstr = cistrstr;
|
||||
+ else if (!strcmp(argv[i], "-s")) { /* case-sensitive item matching */
|
||||
+ fstrncmp = strncmp;
|
||||
+ fstrstr = strstr;
|
||||
} else if (i + 1 == argc)
|
||||
usage();
|
||||
/* these options take one argument */
|
||||
--
|
||||
2.26.2
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
From 39ab9676914bd0d8105d0f96bbd7611a53077438 Mon Sep 17 00:00:00 2001
|
||||
From: Miles Alan <m@milesalan.com>
|
||||
Date: Sat, 4 Jul 2020 11:19:04 -0500
|
||||
Subject: [PATCH] Add -g option to display entries in the given number of grid
|
||||
columns
|
||||
|
||||
This option can be used in conjunction with -l to format dmenu's options in
|
||||
arbitrary size grids. For example, to create a 4 column by 6 line grid, you
|
||||
could use: dmenu -g 4 -l 6
|
||||
---
|
||||
config.def.h | 3 ++-
|
||||
dmenu.1 | 7 ++++++-
|
||||
dmenu.c | 22 ++++++++++++++++------
|
||||
3 files changed, 24 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 1edb647..96cf3c9 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,8 +13,9 @@ static const char *colors[SchemeLast][2] = {
|
||||
[SchemeSel] = { "#eeeeee", "#005577" },
|
||||
[SchemeOut] = { "#000000", "#00ffff" },
|
||||
};
|
||||
-/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
|
||||
+/* -l and -g options; controls number of lines and columns in grid if > 0 */
|
||||
static unsigned int lines = 0;
|
||||
+static unsigned int columns = 0;
|
||||
|
||||
/*
|
||||
* Characters not considered part of a word while deleting words
|
||||
diff --git a/dmenu.1 b/dmenu.1
|
||||
index 323f93c..d0a734a 100644
|
||||
--- a/dmenu.1
|
||||
+++ b/dmenu.1
|
||||
@@ -4,6 +4,8 @@ dmenu \- dynamic menu
|
||||
.SH SYNOPSIS
|
||||
.B dmenu
|
||||
.RB [ \-bfiv ]
|
||||
+.RB [ \-g
|
||||
+.IR columns ]
|
||||
.RB [ \-l
|
||||
.IR lines ]
|
||||
.RB [ \-m
|
||||
@@ -47,8 +49,11 @@ is faster, but will lock up X until stdin reaches end\-of\-file.
|
||||
.B \-i
|
||||
dmenu matches menu items case insensitively.
|
||||
.TP
|
||||
+.BI \-g " columns"
|
||||
+dmenu lists items in a grid with the given number of columns.
|
||||
+.TP
|
||||
.BI \-l " lines"
|
||||
-dmenu lists items vertically, with the given number of lines.
|
||||
+dmenu lists items in a grid with the given number of lines.
|
||||
.TP
|
||||
.BI \-m " monitor"
|
||||
dmenu is displayed on the monitor number supplied. Monitor numbers are starting
|
||||
diff --git a/dmenu.c b/dmenu.c
|
||||
index 6b8f51b..d79b6bb 100644
|
||||
--- a/dmenu.c
|
||||
+++ b/dmenu.c
|
||||
@@ -77,7 +77,7 @@ calcoffsets(void)
|
||||
int i, n;
|
||||
|
||||
if (lines > 0)
|
||||
- n = lines * bh;
|
||||
+ n = lines * columns * bh;
|
||||
else
|
||||
n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
|
||||
/* calculate which items will begin the next page and previous page */
|
||||
@@ -152,9 +152,15 @@ drawmenu(void)
|
||||
}
|
||||
|
||||
if (lines > 0) {
|
||||
- /* draw vertical list */
|
||||
- for (item = curr; item != next; item = item->right)
|
||||
- drawitem(item, x, y += bh, mw - x);
|
||||
+ /* draw grid */
|
||||
+ int i = 0;
|
||||
+ for (item = curr; item != next; item = item->right, i++)
|
||||
+ drawitem(
|
||||
+ item,
|
||||
+ x + ((i / lines) * ((mw - x) / columns)),
|
||||
+ y + (((i % lines) + 1) * bh),
|
||||
+ (mw - x) / columns
|
||||
+ );
|
||||
} else if (matches) {
|
||||
/* draw horizontal list */
|
||||
x += inputw;
|
||||
@@ -708,9 +714,13 @@ main(int argc, char *argv[])
|
||||
} else if (i + 1 == argc)
|
||||
usage();
|
||||
/* these options take one argument */
|
||||
- else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */
|
||||
+ else if (!strcmp(argv[i], "-g")) { /* number of columns in grid */
|
||||
+ columns = atoi(argv[++i]);
|
||||
+ if (lines == 0) lines = 1;
|
||||
+ } else if (!strcmp(argv[i], "-l")) { /* number of lines in grid */
|
||||
lines = atoi(argv[++i]);
|
||||
- else if (!strcmp(argv[i], "-m"))
|
||||
+ if (columns == 0) columns = 1;
|
||||
+ } else if (!strcmp(argv[i], "-m"))
|
||||
mon = atoi(argv[++i]);
|
||||
else if (!strcmp(argv[i], "-p")) /* adds prompt to left of input field */
|
||||
prompt = argv[++i];
|
||||
--
|
||||
2.23.1
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
From 4bf895be219ae00394a5cde901dc43ec6dcb3759 Mon Sep 17 00:00:00 2001
|
||||
From: Tanner Babcock <babkock@gmail.com>
|
||||
Date: Sun, 22 Sep 2019 03:07:26 -0500
|
||||
Subject: [PATCH] Additional color scheme, for adjacent entries
|
||||
|
||||
---
|
||||
config.def.h | 1 +
|
||||
dmenu.c | 4 +++-
|
||||
2 files changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 1edb647..767c88f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -12,6 +12,7 @@ static const char *colors[SchemeLast][2] = {
|
||||
[SchemeNorm] = { "#bbbbbb", "#222222" },
|
||||
[SchemeSel] = { "#eeeeee", "#005577" },
|
||||
[SchemeOut] = { "#000000", "#00ffff" },
|
||||
+ [SchemeMid] = { "#eeeeee", "#770000" },
|
||||
};
|
||||
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
|
||||
static unsigned int lines = 0;
|
||||
diff --git a/dmenu.c b/dmenu.c
|
||||
index 65f25ce..0a5c08d 100644
|
||||
--- a/dmenu.c
|
||||
+++ b/dmenu.c
|
||||
@@ -26,7 +26,7 @@
|
||||
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
||||
|
||||
/* enums */
|
||||
-enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
|
||||
+enum { SchemeNorm, SchemeSel, SchemeOut, SchemeMid, SchemeLast }; /* color schemes */
|
||||
|
||||
struct item {
|
||||
char *text;
|
||||
@@ -118,6 +118,8 @@ drawitem(struct item *item, int x, int y, int w)
|
||||
{
|
||||
if (item == sel)
|
||||
drw_setscheme(drw, scheme[SchemeSel]);
|
||||
+ else if (item->left == sel || item->right == sel)
|
||||
+ drw_setscheme(drw, scheme[SchemeMid]);
|
||||
else if (item->out)
|
||||
drw_setscheme(drw, scheme[SchemeOut]);
|
||||
else
|
||||
--
|
||||
2.23.0
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
diff --git a/dmenu.c b/dmenu.c
|
||||
index d95e6c6..75a79d0 100644
|
||||
--- a/dmenu.c
|
||||
+++ b/dmenu.c
|
||||
@@ -518,6 +518,119 @@ draw:
|
||||
drawmenu();
|
||||
}
|
||||
|
||||
+static void
|
||||
+buttonpress(XEvent *e)
|
||||
+{
|
||||
+ struct item *item;
|
||||
+ XButtonPressedEvent *ev = &e->xbutton;
|
||||
+ int x = 0, y = 0, h = bh, w;
|
||||
+
|
||||
+ if (ev->window != win)
|
||||
+ return;
|
||||
+
|
||||
+ /* right-click: exit */
|
||||
+ if (ev->button == Button3)
|
||||
+ exit(1);
|
||||
+
|
||||
+ if (prompt && *prompt)
|
||||
+ x += promptw;
|
||||
+
|
||||
+ /* input field */
|
||||
+ w = (lines > 0 || !matches) ? mw - x : inputw;
|
||||
+
|
||||
+ /* left-click on input: clear input,
|
||||
+ * NOTE: if there is no left-arrow the space for < is reserved so
|
||||
+ * add that to the input width */
|
||||
+ if (ev->button == Button1 &&
|
||||
+ ((lines <= 0 && ev->x >= 0 && ev->x <= x + w +
|
||||
+ ((!prev || !curr->left) ? TEXTW("<") : 0)) ||
|
||||
+ (lines > 0 && ev->y >= y && ev->y <= y + h))) {
|
||||
+ insert(NULL, -cursor);
|
||||
+ drawmenu();
|
||||
+ return;
|
||||
+ }
|
||||
+ /* middle-mouse click: paste selection */
|
||||
+ if (ev->button == Button2) {
|
||||
+ XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
|
||||
+ utf8, utf8, win, CurrentTime);
|
||||
+ drawmenu();
|
||||
+ return;
|
||||
+ }
|
||||
+ /* scroll up */
|
||||
+ if (ev->button == Button4 && prev) {
|
||||
+ sel = curr = prev;
|
||||
+ calcoffsets();
|
||||
+ drawmenu();
|
||||
+ return;
|
||||
+ }
|
||||
+ /* scroll down */
|
||||
+ if (ev->button == Button5 && next) {
|
||||
+ sel = curr = next;
|
||||
+ calcoffsets();
|
||||
+ drawmenu();
|
||||
+ return;
|
||||
+ }
|
||||
+ if (ev->button != Button1)
|
||||
+ return;
|
||||
+ if (ev->state & ~ControlMask)
|
||||
+ return;
|
||||
+ if (lines > 0) {
|
||||
+ /* vertical list: (ctrl)left-click on item */
|
||||
+ w = mw - x;
|
||||
+ for (item = curr; item != next; item = item->right) {
|
||||
+ y += h;
|
||||
+ if (ev->y >= y && ev->y <= (y + h)) {
|
||||
+ puts(item->text);
|
||||
+ if (!(ev->state & ControlMask))
|
||||
+ exit(0);
|
||||
+ sel = item;
|
||||
+ if (sel) {
|
||||
+ sel->out = 1;
|
||||
+ drawmenu();
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ } else if (matches) {
|
||||
+ /* left-click on left arrow */
|
||||
+ x += inputw;
|
||||
+ w = TEXTW("<");
|
||||
+ if (prev && curr->left) {
|
||||
+ if (ev->x >= x && ev->x <= x + w) {
|
||||
+ sel = curr = prev;
|
||||
+ calcoffsets();
|
||||
+ drawmenu();
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ /* horizontal list: (ctrl)left-click on item */
|
||||
+ for (item = curr; item != next; item = item->right) {
|
||||
+ x += w;
|
||||
+ w = MIN(TEXTW(item->text), mw - x - TEXTW(">"));
|
||||
+ if (ev->x >= x && ev->x <= x + w) {
|
||||
+ puts(item->text);
|
||||
+ if (!(ev->state & ControlMask))
|
||||
+ exit(0);
|
||||
+ sel = item;
|
||||
+ if (sel) {
|
||||
+ sel->out = 1;
|
||||
+ drawmenu();
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ /* left-click on right arrow */
|
||||
+ w = TEXTW(">");
|
||||
+ x = mw - w;
|
||||
+ if (next && ev->x >= x && ev->x <= x + w) {
|
||||
+ sel = curr = next;
|
||||
+ calcoffsets();
|
||||
+ drawmenu();
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void
|
||||
paste(void)
|
||||
{
|
||||
@@ -579,6 +692,9 @@ run(void)
|
||||
break;
|
||||
cleanup();
|
||||
exit(1);
|
||||
+ case ButtonPress:
|
||||
+ buttonpress(&ev);
|
||||
+ break;
|
||||
case Expose:
|
||||
if (ev.xexpose.count == 0)
|
||||
drw_map(drw, win, 0, 0, mw, mh);
|
||||
@@ -676,7 +792,8 @@ setup(void)
|
||||
/* create menu window */
|
||||
swa.override_redirect = True;
|
||||
swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
||||
- swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
|
||||
+ swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask |
|
||||
+ ButtonPressMask;
|
||||
win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
|
||||
CopyFromParent, CopyFromParent, CopyFromParent,
|
||||
CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
|
|
@ -1,245 +0,0 @@
|
|||
diff --git a/dmenu.c b/dmenu.c
|
||||
index 5c835dd..71efe52 100644
|
||||
--- a/dmenu.c
|
||||
+++ b/dmenu.c
|
||||
@@ -131,9 +131,10 @@ drawitem(struct item *item, int x, int y, int w)
|
||||
static void
|
||||
drawmenu(void)
|
||||
{
|
||||
- unsigned int curpos;
|
||||
+ static int curpos, oldcurlen;
|
||||
struct item *item;
|
||||
int x = 0, y = 0, w;
|
||||
+ int curlen, rcurlen;
|
||||
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
drw_rect(drw, 0, 0, mw, mh, 1, 1);
|
||||
@@ -144,14 +145,21 @@ drawmenu(void)
|
||||
}
|
||||
/* draw input field */
|
||||
w = (lines > 0 || !matches) ? mw - x : inputw;
|
||||
- drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
- drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
|
||||
+ w -= lrpad / 2;
|
||||
+ x += lrpad / 2;
|
||||
|
||||
- curpos = TEXTW(text) - TEXTW(&text[cursor]);
|
||||
- if ((curpos += lrpad / 2 - 1) < w) {
|
||||
- drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
- drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
|
||||
- }
|
||||
+ rcurlen = drw_fontset_getwidth(drw, text + cursor);
|
||||
+ curlen = drw_fontset_getwidth(drw, text) - rcurlen;
|
||||
+ curpos += curlen - oldcurlen;
|
||||
+ curpos = MIN(w, MAX(0, curpos));
|
||||
+ curpos = MAX(curpos, w - rcurlen);
|
||||
+ curpos = MIN(curpos, curlen);
|
||||
+ oldcurlen = curlen;
|
||||
+
|
||||
+ drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
+ drw_text_align(drw, x, 0, curpos, bh, text, cursor, AlignR);
|
||||
+ drw_text_align(drw, x + curpos, 0, w - curpos, bh, text + cursor, strlen(text) - cursor, AlignL);
|
||||
+ drw_rect(drw, x + curpos - 1, 2, 2, bh - 4, 1, 0);
|
||||
|
||||
if (lines > 0) {
|
||||
/* draw vertical list */
|
||||
diff --git a/drw.c b/drw.c
|
||||
index c638323..bfffbc1 100644
|
||||
--- a/drw.c
|
||||
+++ b/drw.c
|
||||
@@ -364,6 +364,175 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
return x + (render ? w : 0);
|
||||
}
|
||||
|
||||
+int
|
||||
+utf8nextchar(const char *str, int len, int i, int inc)
|
||||
+{
|
||||
+ int n;
|
||||
+
|
||||
+ for (n = i + inc; n + inc >= 0 && n + inc <= len
|
||||
+ && (str[n] & 0xc0) == 0x80; n += inc)
|
||||
+ ;
|
||||
+ return n;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align)
|
||||
+{
|
||||
+ int ty;
|
||||
+ unsigned int ew;
|
||||
+ XftDraw *d = NULL;
|
||||
+ Fnt *usedfont, *curfont, *nextfont;
|
||||
+ size_t 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;
|
||||
+ int i, n;
|
||||
+
|
||||
+ if (!drw || (render && !drw->scheme) || !text || !drw->fonts || textlen <= 0
|
||||
+ || (align != AlignL && align != AlignR))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (!render) {
|
||||
+ w = ~w;
|
||||
+ } else {
|
||||
+ XSetForeground(drw->dpy, drw->gc, drw->scheme[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));
|
||||
+ }
|
||||
+
|
||||
+ usedfont = drw->fonts;
|
||||
+ i = align == AlignL ? 0 : textlen;
|
||||
+ x = align == AlignL ? x : x + w;
|
||||
+ while (1) {
|
||||
+ utf8strlen = 0;
|
||||
+ nextfont = NULL;
|
||||
+ /* if (align == AlignL) */
|
||||
+ utf8str = text + i;
|
||||
+
|
||||
+ while ((align == AlignL && i < textlen) || (align == AlignR && i > 0)) {
|
||||
+ if (align == AlignL) {
|
||||
+ utf8charlen = utf8decode(text + i, &utf8codepoint, MIN(textlen - i, UTF_SIZ));
|
||||
+ if (!utf8charlen) {
|
||||
+ textlen = i;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ n = utf8nextchar(text, textlen, i, -1);
|
||||
+ utf8charlen = utf8decode(text + n, &utf8codepoint, MIN(textlen - n, UTF_SIZ));
|
||||
+ if (!utf8charlen) {
|
||||
+ textlen -= i;
|
||||
+ text += i;
|
||||
+ i = 0;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ for (curfont = drw->fonts; curfont; curfont = curfont->next) {
|
||||
+ charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
|
||||
+ if (charexists) {
|
||||
+ if (curfont == usedfont) {
|
||||
+ utf8strlen += utf8charlen;
|
||||
+ i += align == AlignL ? utf8charlen : -utf8charlen;
|
||||
+ } else {
|
||||
+ nextfont = curfont;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!charexists || nextfont)
|
||||
+ break;
|
||||
+ else
|
||||
+ charexists = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (align == AlignR)
|
||||
+ utf8str = text + i;
|
||||
+
|
||||
+ if (utf8strlen) {
|
||||
+ drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
|
||||
+ /* shorten text if necessary */
|
||||
+ if (align == AlignL) {
|
||||
+ for (len = utf8strlen; len && ew > w; ) {
|
||||
+ len = utf8nextchar(utf8str, len, len, -1);
|
||||
+ drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
|
||||
+ }
|
||||
+ } else {
|
||||
+ for (len = utf8strlen; len && ew > w; ) {
|
||||
+ n = utf8nextchar(utf8str, len, 0, +1);
|
||||
+ utf8str += n;
|
||||
+ len -= n;
|
||||
+ drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (len) {
|
||||
+ if (render) {
|
||||
+ ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
|
||||
+ XftDrawStringUtf8(d, &drw->scheme[ColFg],
|
||||
+ usedfont->xfont, align == AlignL ? x : x - ew, ty, (XftChar8 *)utf8str, len);
|
||||
+ }
|
||||
+ x += align == AlignL ? ew : -ew;
|
||||
+ w -= ew;
|
||||
+ }
|
||||
+ if (len < utf8strlen)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if ((align == AlignR && i <= 0) || (align == AlignL && i >= textlen)) {
|
||||
+ 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);
|
||||
+
|
||||
+ 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;
|
||||
+}
|
||||
+
|
||||
void
|
||||
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
|
||||
{
|
||||
diff --git a/drw.h b/drw.h
|
||||
index 4c67419..b66a83e 100644
|
||||
--- a/drw.h
|
||||
+++ b/drw.h
|
||||
@@ -13,6 +13,7 @@ typedef struct Fnt {
|
||||
} Fnt;
|
||||
|
||||
enum { ColFg, ColBg }; /* Clr scheme index */
|
||||
+enum { AlignL, AlignR };
|
||||
typedef XftColor Clr;
|
||||
|
||||
typedef struct {
|
||||
@@ -52,6 +53,7 @@ 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);
|
||||
+int drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align);
|
||||
|
||||
/* Map functions */
|
||||
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
|
|
@ -1,46 +0,0 @@
|
|||
#!/bin/sh
|
||||
# dfmpeg
|
||||
# dmenu gui for recording your screen with ffmpeg
|
||||
# Licensed under MIT, written by speedie
|
||||
# https://github.com/speediegamer/dfmpeg
|
||||
|
||||
defaultConfig() {
|
||||
DFMPEG_DOTDIR="$HOME/.config/dfmpeg" # The directory where dotfiles are
|
||||
DFMPEG_RESOLUTION="1920x1080" # The resolution to record in
|
||||
DFMPEG_AUDIO_DEVICE="alsa" # How to capture audio (alsa/pulseaudio)
|
||||
DFMPEG_FRAME_RATE="60" # Frame rate to capture in.
|
||||
DFMPEG_RECORD_DEVICE="x11grab" # Probably do not change.
|
||||
DFMPEG_OUTPUT_PATH="$HOME/Videos" # Path where videos will be saved.
|
||||
DFMPEG_OUTPUT_FORMAT="mp4" # What format to use
|
||||
DFMPEG_OUTPUT_FILENAME="$DFMPEG_OUTPUT_PATH/Dfmpeg-Output-$(date +"%d-%d-%y-%T").$DFMPEG_OUTPUT_FORMAT" # File name of the output. Probably don't need to change.
|
||||
DFMPEG_WH=":0.0" # Width and height, no need to change, defaults should work.
|
||||
DFMPEG_DMENU="dmenu" # Path to dmenu
|
||||
DFMPEG_TERM="$TERMINAL" # Terminal to use when editing the configuration file.
|
||||
DFMPEG_EDITOR="vim" # Editor to edit the config file with
|
||||
}
|
||||
|
||||
defaultConfig
|
||||
. "$DFMPEG_DOTDIR"/dfmpegrc
|
||||
startrec="ffmpeg -f $DFMPEG_RECORD_DEVICE -s $DFMPEG_RESOLUTION -i $DFMPEG_WH -f $DFMPEG_AUDIO_DEVICE -r $DFMPEG_FRAME_RATE -i default $DFMPEG_OUTPUT_FILENAME"
|
||||
startrec_no_audio="ffmpeg -f $DFMPEG_RECORD_DEVICE -s $DFMPEG_RESOLUTION -r $DFMPEG_FRAME_RATE -i $DFMPEG_WH $DFMPEG_OUTPUT_FILENAME"
|
||||
stoprec="pkill ffmpeg"
|
||||
dfmpeg_ver="2022-04-03-r1"
|
||||
about_screen="dfmpeg $dfmpeg_ver."
|
||||
about_screen_2="Licensed under MIT, written by speedie + contributors."
|
||||
about_screen_3="https://github.com/speediegamer/dfmpeg"
|
||||
|
||||
case "$(printf 'Start\nStop\nStart-No-Audio\nConfigure\nExit\nAbout' | dmenu -p 'Record your screen:')" in
|
||||
"Exit") DFMPEG_STATUS=idle && exit 0 ;;
|
||||
"Start") DFMPEG_STATUS=recording && touch /tmp/dfmpeg-recording && $startrec && exit 0 ;;
|
||||
"Stop") $stoprec && rm /tmp/dfmpeg-recording && DFMPEG_STATUS=idle ;;
|
||||
"Configure") $DFMPEG_TERM $DFMPEG_EDITOR $DFMPEG_DOTDIR/dfmpegrc ;;
|
||||
"Start-No-Audio") DFMPEG_STATUS=recording && touch /tmp/dfmpeg-recording && $startrec_no_audio && exit 0 ;;
|
||||
"About")
|
||||
echo $about_screen > $DFMPEG_DOTDIR/dfmpeg_about
|
||||
echo $about_screen_2 >> $DFMPEG_DOTDIR/dfmpeg_about
|
||||
echo $about_screen_3 >> $DFMPEG_DOTDIR/dfmpeg_about
|
||||
$DFMPEG_TERM $DFMPEG_EDITOR $DFMPEG_DOTDIR/dfmpeg_about
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0 # This fixes a small bug.
|
3
dwm-flexipatch/.github/FUNDING.yml
vendored
3
dwm-flexipatch/.github/FUNDING.yml
vendored
|
@ -1,3 +0,0 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
custom: ["https://suckless.org/donations/", "https://paypal.me/dwmflexipatch"]
|
|
@ -168,45 +168,45 @@ static const char dmenufont[] = "Hack Nerd Font:size=11";
|
|||
|
||||
static char c000000[] = "#000000"; // placeholder value
|
||||
|
||||
static char normfgcolor[] = "#bbbbbb";
|
||||
static char normbgcolor[] = "#222222";
|
||||
static char normbordercolor[] = "#444444";
|
||||
static char normfloatcolor[] = "#db8fd9";
|
||||
static char normfgcolor[] = "#ffffff";
|
||||
static char normbgcolor[] = "#173f4f";
|
||||
static char normbordercolor[] = "#173f4f";
|
||||
static char normfloatcolor[] = "#124f5f";
|
||||
|
||||
static char selfgcolor[] = "#eeeeee";
|
||||
static char selbgcolor[] = "#005577";
|
||||
static char selbordercolor[] = "#005577";
|
||||
static char selfloatcolor[] = "#005577";
|
||||
static char selbgcolor[] = "#153a49";
|
||||
static char selbordercolor[] = "#153a49";
|
||||
static char selfloatcolor[] = "#153a49";
|
||||
|
||||
static char titlenormfgcolor[] = "#bbbbbb";
|
||||
static char titlenormbgcolor[] = "#222222";
|
||||
static char titlenormbordercolor[] = "#444444";
|
||||
static char titlenormfloatcolor[] = "#db8fd9";
|
||||
static char titlenormfgcolor[] = "#ffffff";
|
||||
static char titlenormbgcolor[] = "#173f4f";
|
||||
static char titlenormbordercolor[] = "#173f4f";
|
||||
static char titlenormfloatcolor[] = "#124f5f";
|
||||
|
||||
static char titleselfgcolor[] = "#eeeeee";
|
||||
static char titleselbgcolor[] = "#005577";
|
||||
static char titleselbordercolor[] = "#005577";
|
||||
static char titleselfloatcolor[] = "#005577";
|
||||
static char titleselbgcolor[] = "#153a49";
|
||||
static char titleselbordercolor[] = "#153a49";
|
||||
static char titleselfloatcolor[] = "#153a49";
|
||||
|
||||
static char tagsnormfgcolor[] = "#bbbbbb";
|
||||
static char tagsnormbgcolor[] = "#222222";
|
||||
static char tagsnormbordercolor[] = "#444444";
|
||||
static char tagsnormfloatcolor[] = "#db8fd9";
|
||||
static char tagsnormfgcolor[] = "#ffffff";
|
||||
static char tagsnormbgcolor[] = "#173f4f";
|
||||
static char tagsnormbordercolor[] = "#173f4f";
|
||||
static char tagsnormfloatcolor[] = "#124f5f";
|
||||
|
||||
static char tagsselfgcolor[] = "#eeeeee";
|
||||
static char tagsselbgcolor[] = "#005577";
|
||||
static char tagsselbordercolor[] = "#005577";
|
||||
static char tagsselfloatcolor[] = "#005577";
|
||||
static char tagsselbgcolor[] = "#153a49";
|
||||
static char tagsselbordercolor[] = "#153a49";
|
||||
static char tagsselfloatcolor[] = "#153a49";
|
||||
|
||||
static char hidnormfgcolor[] = "#005577";
|
||||
static char hidnormfgcolor[] = "#153a49";
|
||||
static char hidselfgcolor[] = "#227799";
|
||||
static char hidnormbgcolor[] = "#222222";
|
||||
static char hidselbgcolor[] = "#222222";
|
||||
static char hidnormbgcolor[] = "#173f4f";
|
||||
static char hidselbgcolor[] = "#173f4f";
|
||||
|
||||
static char urgfgcolor[] = "#bbbbbb";
|
||||
static char urgbgcolor[] = "#222222";
|
||||
static char urgfgcolor[] = "#ffffff";
|
||||
static char urgbgcolor[] = "#173f4f";
|
||||
static char urgbordercolor[] = "#ff0000";
|
||||
static char urgfloatcolor[] = "#db8fd9";
|
||||
static char urgfloatcolor[] = "#124f5f";
|
||||
|
||||
#if RENAMED_SCRATCHPADS_PATCH
|
||||
static char scratchselfgcolor[] = "#FFF7D4";
|
||||
|
@ -905,7 +905,7 @@ static const Key keys[] = {
|
|||
{ Mod4Mask, XK_f, spawn, SHCMD("spmenu_run -fm -a '-g 4 -l 10'") },
|
||||
/* spmenu scripts down here */
|
||||
{ Mod4Mask, XK_v, spawn, SHCMD("clipmenu-spmenu") },
|
||||
{ Mod4Mask|ShiftMask, XK_Print, spawn, SHCMD("screenshot-spmenu -f") },
|
||||
{ Mod4Mask, XK_Print, spawn, SHCMD("screenshot-spmenu -f") },
|
||||
{ Mod4Mask|Mod1Mask, XK_Print, spawn, SHCMD("screenshot-spmenu -s") },
|
||||
{ Mod4Mask, XK_p, spawn, SHCMD("pirokit") },
|
||||
{ Mod4Mask|ShiftMask, XK_w, spawn, SHCMD("wallpaper-spmenu") },
|
||||
|
@ -917,6 +917,8 @@ static const Key keys[] = {
|
|||
{ Mod4Mask, XK_u, spawn, SHCMD("volume-dunst up") },
|
||||
{ Mod4Mask, XK_d, spawn, SHCMD("volume-dunst down") },
|
||||
{ Mod4Mask, XK_m, spawn, SHCMD("volume-dunst mute") },
|
||||
/* slock must be installed */
|
||||
{ Mod4Mask, XK_l, spawn, SHCMD("slock") },
|
||||
#if KEYMODES_PATCH
|
||||
{ MODKEY, XK_Escape, setkeymode, {.ui = COMMANDMODE} },
|
||||
#endif // KEYMODES_PATCH
|
||||
|
@ -930,7 +932,6 @@ static const Key keys[] = {
|
|||
{ MODKEY|ShiftMask, XK_t, spawn, SHCMD("tabbed -r 2 st -w ''") },
|
||||
{ MODKEY|ShiftMask, XK_i, spawn, SHCMD("firefox") },
|
||||
{ Mod4Mask, XK_e, spawn, SHCMD("st -T sfm sfm") },
|
||||
{ Mod4Mask, XK_Print, spawn, SHCMD("maim ~/Pictures/Screenshot_$(date +%s).png") },
|
||||
#endif // RIODRAW_PATCH
|
||||
{ MODKEY, XK_b, togglebar, {0} },
|
||||
#if TOGGLETOPBAR_PATCH
|
||||
|
|
|
@ -46,7 +46,7 @@ XRENDER = -lXrender
|
|||
XEXTLIB = -lXext
|
||||
|
||||
# Uncomment this for the swallow patch / SWALLOW_PATCH
|
||||
#XCBLIBS = -lX11-xcb -lxcb -lxcb-res
|
||||
XCBLIBS = -lX11-xcb -lxcb -lxcb-res
|
||||
|
||||
# This is needed for the winicon and tagpreview patches / BAR_WINICON_PATCH / BAR_TAGPREVIEW_PATCH
|
||||
IMLIB2LIBS = -lImlib2
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Name=Dwm
|
||||
Name=dwm-flexipatch (X11)
|
||||
Comment=Dynamic window manager
|
||||
Exec=dwm
|
||||
Exec=/usr/local/bin/startdwm
|
||||
Icon=dwm
|
||||
Type=XSession
|
||||
|
|
|
@ -16,47 +16,47 @@ loadxrdb()
|
|||
xrdb = XrmGetStringDatabase(resm);
|
||||
|
||||
if (xrdb != NULL) {
|
||||
XRDB_LOAD_COLOR("dwm.color0", normbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.color15", normfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color0", normbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color4", normfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color8", selbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.color4", selbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color10", normbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.color10", normfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color0", selfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.selbordercolor", selbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.selfloatcolor", selfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.titlenormfgcolor", titlenormfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.titlenormbgcolor", titlenormbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.titlenormbordercolor", titlenormbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.titlenormfloatcolor", titlenormfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.titleselfgcolor", titleselfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.titleselbgcolor", titleselbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.titleselbordercolor", titleselbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.titleselfloatcolor", titleselfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.tagsnormfgcolor", tagsnormfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.tagsnormbgcolor", tagsnormbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.tagsnormbordercolor", tagsnormbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.tagsnormfloatcolor", tagsnormfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.tagsselfgcolor", tagsselfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.tagsselbgcolor", tagsselbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.tagsselbordercolor", tagsselbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.tagsselfloatcolor", tagsselfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.hidnormfgcolor", hidnormfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.hidnormbgcolor", hidnormbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.hidselfgcolor", hidselfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.hidselbgcolor", hidselbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.urgfgcolor", urgfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.urgbgcolor", urgbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.urgbordercolor", urgbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.urgfloatcolor", urgfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color14", selbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color12", selbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.color12", selfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color15", titlenormfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color0", titlenormbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color10", titlenormbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.color10", titlenormfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color0", titleselfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color14", titleselbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color12", titleselbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.color12", titleselfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color15", tagsnormfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color0", tagsnormbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color10", tagsnormbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.color10", tagsnormfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color0", tagsselfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color14", tagsselbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color12", tagsselbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.color12", tagsselfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color15", hidnormfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color0", hidnormbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color0", hidselfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color14", hidselbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color15", urgfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color3", urgbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color11", urgbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.color11", urgfloatcolor);
|
||||
#if RENAMED_SCRATCHPADS_PATCH
|
||||
XRDB_LOAD_COLOR("dwm.scratchselfgcolor", scratchselfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.scratchselbgcolor", scratchselbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.scratchselbordercolor", scratchselbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.scratchselfloatcolor", scratchselfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.scratchnormfgcolor", scratchnormfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.scratchnormbgcolor", scratchnormbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.scratchnormbordercolor", scratchnormbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.scratchnormfloatcolor", scratchnormfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color0", scratchselfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color14", scratchselbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color14", scratchselbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.color14", scratchselfloatcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color8", scratchnormfgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color13", scratchnormbgcolor);
|
||||
XRDB_LOAD_COLOR("dwm.color13", scratchnormbordercolor);
|
||||
XRDB_LOAD_COLOR("dwm.color13", scratchnormfloatcolor);
|
||||
#endif // RENAMED_SCRATCHPADS_PATCH
|
||||
#if BAR_FLEXWINTITLE_PATCH
|
||||
XRDB_LOAD_COLOR("dwm.normTTBbgcolor", normTTBbgcolor);
|
||||
|
|
|
@ -130,7 +130,7 @@
|
|||
*
|
||||
* https://dwm.suckless.org/patches/tag-previews/
|
||||
*/
|
||||
#define BAR_TAGPREVIEW_PATCH 0
|
||||
#define BAR_TAGPREVIEW_PATCH 1
|
||||
|
||||
/* Show status in bar */
|
||||
#define BAR_STATUS_PATCH 1
|
||||
|
@ -423,7 +423,7 @@
|
|||
* Essentially this way the colors you use in your regular tty is "mirrored" to dwm.
|
||||
* https://dwm.suckless.org/patches/vtcolors/
|
||||
*/
|
||||
#define BAR_VTCOLORS_PATCH 1
|
||||
#define BAR_VTCOLORS_PATCH 0
|
||||
|
||||
/* This patch allows client windows to be hidden. This code was originally part of awesomebar,
|
||||
* but has been separated out so that other bar modules can take advantage of it.
|
||||
|
@ -532,7 +532,7 @@
|
|||
* respective stack in tiled layout.
|
||||
* https://dwm.suckless.org/patches/cfacts/
|
||||
*/
|
||||
#define CFACTS_PATCH 0
|
||||
#define CFACTS_PATCH 1
|
||||
|
||||
/* This patch allows color attributes to be set through the command line.
|
||||
* https://dwm.suckless.org/patches/cmdcustomize/
|
||||
|
@ -575,14 +575,14 @@
|
|||
/* Similarly to the dragmfact patch this allows you to click and drag clients to change the
|
||||
* cfact to adjust the client's size in the stack. This patch depends on the cfacts patch.
|
||||
*/
|
||||
#define DRAGCFACT_PATCH 0
|
||||
#define DRAGCFACT_PATCH 1
|
||||
|
||||
/* This patch lets you resize the split in the tile layout (i.e. modify mfact) by holding
|
||||
* the modkey and dragging the mouse.
|
||||
* This patch can be a bit wonky with other layouts, but generally works.
|
||||
* https://dwm.suckless.org/patches/dragmfact/
|
||||
*/
|
||||
#define DRAGMFACT_PATCH 0
|
||||
#define DRAGMFACT_PATCH 1
|
||||
|
||||
/* Simple dwmc client using a fork of fsignal to communicate with dwm.
|
||||
* To use this either copy the patch/dwmc shell script to somewhere in your path or
|
||||
|
@ -597,7 +597,7 @@
|
|||
* it will be opened on the first tag.
|
||||
* https://dwm.suckless.org/patches/emptyview/
|
||||
*/
|
||||
#define EMPTYVIEW_PATCH 0
|
||||
#define EMPTYVIEW_PATCH 1
|
||||
|
||||
/* This patch allows the user to change size and placement of floating windows using only the
|
||||
* keyboard. It also allows for temporary vertical and horizontal extension of windows similar
|
||||
|
@ -612,7 +612,7 @@
|
|||
* This patch takes precedence over the fakefullscreen client patch below.
|
||||
* https://dwm.suckless.org/patches/fakefullscreen/
|
||||
*/
|
||||
#define FAKEFULLSCREEN_PATCH 0
|
||||
#define FAKEFULLSCREEN_PATCH 1
|
||||
|
||||
/* Similarly to the fakefullscreen patch this patch only allows clients to "fullscreen" into
|
||||
* the space currently given to them.
|
||||
|
@ -826,13 +826,13 @@
|
|||
/* Removes the border when there is only one window visible.
|
||||
* https://dwm.suckless.org/patches/noborder/
|
||||
*/
|
||||
#define NOBORDER_PATCH 0
|
||||
#define NOBORDER_PATCH 1
|
||||
|
||||
/* Enable modifying or removing dmenu in config.def.h which resulted previously in a
|
||||
* compilation error because two lines of code hardcode dmenu into dwm.
|
||||
* https://dwm.suckless.org/patches/nodmenu/
|
||||
*/
|
||||
#define NODMENU_PATCH 0
|
||||
#define NODMENU_PATCH 1
|
||||
|
||||
/* This patch allows for toggleable client button bindings that have no modifiers.
|
||||
* This can, for example, allow you to move or resize using the mouse alone without holding
|
||||
|
@ -948,7 +948,7 @@
|
|||
* Additionally dwm can quit cleanly by using kill -TERM dwmpid.
|
||||
* https://dwm.suckless.org/patches/restartsig/
|
||||
*/
|
||||
#define RESTARTSIG_PATCH 0
|
||||
#define RESTARTSIG_PATCH 1
|
||||
|
||||
/* Adds rio-like drawing to resize the selected client.
|
||||
* This depends on an external tool slop being installed.
|
||||
|
@ -987,10 +987,10 @@
|
|||
* https://lists.suckless.org/hackers/2004/17205.html
|
||||
* https://dwm.suckless.org/patches/scratchpads/
|
||||
*/
|
||||
#define SCRATCHPADS_PATCH 0
|
||||
#define SCRATCHPADS_PATCH 1
|
||||
|
||||
/* Minor alteration of the above allowing clients to keep their size and position when shown */
|
||||
#define SCRATCHPADS_KEEP_POSITION_AND_SIZE_PATCH 0
|
||||
#define SCRATCHPADS_KEEP_POSITION_AND_SIZE_PATCH 1
|
||||
|
||||
/* This alternative patch enables a scratchpad feature in dwm similar to the scratchpad
|
||||
* feature in i3wm.
|
||||
|
@ -1064,7 +1064,7 @@
|
|||
/* This variant of the shiftview patch adds left and right circular shift through tags,
|
||||
* but skips tags where there are no clients.
|
||||
*/
|
||||
#define SHIFTVIEW_CLIENTS_PATCH 0
|
||||
#define SHIFTVIEW_CLIENTS_PATCH 1
|
||||
|
||||
/* This patch makes dwm obey even "soft" sizehints for new clients. Any window
|
||||
* that requests a specific initial size will be floated and set to that size.
|
||||
|
@ -1133,7 +1133,7 @@
|
|||
/* Adds toggleable keyboard shortcut to make a client 'sticky', i.e. visible on all tags.
|
||||
* https://dwm.suckless.org/patches/sticky/
|
||||
*/
|
||||
#define STICKY_PATCH 0
|
||||
#define STICKY_PATCH 1
|
||||
|
||||
/* This patch adds "window swallowing" to dwm as known from Plan 9's windowing system rio.
|
||||
* Clients marked with isterminal in config.h swallow a window opened by any child process,
|
||||
|
@ -1150,7 +1150,7 @@
|
|||
*
|
||||
* https://dwm.suckless.org/patches/swallow/
|
||||
*/
|
||||
#define SWALLOW_PATCH 0
|
||||
#define SWALLOW_PATCH 1
|
||||
|
||||
/* This patch depends on the pertag patch and makes it possible to switch focus with a single
|
||||
* shortcut (MOD+s) instead of having to think if you should use mod-j or mod-k for reaching
|
||||
|
@ -1199,7 +1199,7 @@
|
|||
/* Adds keyboard shortcuts to move all (or only floating) windows from one tag to another.
|
||||
* https://dwm.suckless.org/patches/tagall/
|
||||
*/
|
||||
#define TAGALL_PATCH 0
|
||||
#define TAGALL_PATCH 1
|
||||
|
||||
/* This patch allows you to move all visible windows on a monitor to an adjacent monitor.
|
||||
* https://github.com/bakkeby/patches/blob/master/dwm/dwm-tagallmon-6.2.diff
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
#!/bin/sh
|
||||
systemctl --user restart clipmenud.service
|
||||
xrdb -merge ~/.Xresources &
|
||||
/usr/local/bin/slstatus &
|
||||
paplay /usr/share/sounds/Oxygen-Sys-Special.ogg
|
||||
exec ./dwm
|
6
dwmblocks-async/.clang-format
Normal file
6
dwmblocks-async/.clang-format
Normal file
|
@ -0,0 +1,6 @@
|
|||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 79
|
||||
AlignArrayOfStructures: Left
|
||||
AlignConsecutiveMacros: true
|
||||
AllowShortFunctionsOnASingleLine: None
|
6
dwmblocks-async/.clangd
Normal file
6
dwmblocks-async/.clangd
Normal file
|
@ -0,0 +1,6 @@
|
|||
CompileFlags:
|
||||
Add:
|
||||
- "-I."
|
||||
- "-I./inc"
|
||||
- "-I.."
|
||||
- "-I../inc"
|
3
dwmblocks-async/.gitignore
vendored
Normal file
3
dwmblocks-async/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
build/
|
||||
.cache/
|
||||
dwmblocks
|
339
dwmblocks-async/LICENSE
Normal file
339
dwmblocks-async/LICENSE
Normal file
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
54
dwmblocks-async/Makefile
Normal file
54
dwmblocks-async/Makefile
Normal file
|
@ -0,0 +1,54 @@
|
|||
.POSIX:
|
||||
|
||||
BIN := dwmblocks
|
||||
BUILD_DIR := build
|
||||
SRC_DIR := src
|
||||
INC_DIR := inc
|
||||
|
||||
VERBOSE := 0
|
||||
|
||||
PREFIX := /usr/local
|
||||
CC = cc
|
||||
CFLAGS := -Wall -Wextra -Ofast -I. -I$(INC_DIR)
|
||||
CFLAGS += -Wall -Wextra -Wno-missing-field-initializers
|
||||
LDLIBS := -lX11
|
||||
|
||||
VPATH := $(SRC_DIR)
|
||||
OBJS := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(wildcard $(SRC_DIR)/*.c))
|
||||
OBJS += $(patsubst %.c,$(BUILD_DIR)/%.o,$(wildcard *.c))
|
||||
|
||||
INSTALL_DIR := $(DESTDIR)$(PREFIX)/bin
|
||||
|
||||
# Prettify output
|
||||
PRINTF := @printf "%-8s %s\n"
|
||||
ifeq ($(VERBOSE), 0)
|
||||
Q := @
|
||||
endif
|
||||
|
||||
all: $(BUILD_DIR)/$(BIN)
|
||||
|
||||
$(BUILD_DIR)/$(BIN): $(OBJS)
|
||||
$(PRINTF) "LD" $@
|
||||
$Q$(LINK.o) $^ $(LDLIBS) -o $@
|
||||
|
||||
$(BUILD_DIR)/%.o: %.c config.h | $(BUILD_DIR)
|
||||
$(PRINTF) "CC" $@
|
||||
$Q$(COMPILE.c) -o $@ $<
|
||||
|
||||
$(BUILD_DIR):
|
||||
$(PRINTF) "MKDIR" $@
|
||||
$Qmkdir -p $@
|
||||
|
||||
clean:
|
||||
$(PRINTF) "CLEAN" $(BUILD_DIR)
|
||||
$Q$(RM) $(BUILD_DIR)/*
|
||||
|
||||
install: $(BUILD_DIR)/$(BIN)
|
||||
$(PRINTF) "INSTALL" $(INSTALL_DIR)/$(BIN)
|
||||
$Qinstall -D -m 755 $< $(INSTALL_DIR)/$(BIN)
|
||||
|
||||
uninstall:
|
||||
$(PRINTF) "RM" $(INSTALL_DIR)/$(BIN)
|
||||
$Q$(RM) $(INSTALL_DIR)/$(BIN)
|
||||
|
||||
.PHONY: all clean install uninstall
|
161
dwmblocks-async/README.md
Normal file
161
dwmblocks-async/README.md
Normal file
|
@ -0,0 +1,161 @@
|
|||
# dwmblocks-async
|
||||
|
||||
A [`dwm`](https://dwm.suckless.org) status bar that has a modular, async
|
||||
design, so it is always responsive. Imagine `i3blocks`, but for `dwm`.
|
||||
|
||||
![A lean config of dwmblocks-async.](preview.png)
|
||||
|
||||
## Features
|
||||
|
||||
- [Modular](#modifying-the-blocks)
|
||||
- Lightweight
|
||||
- [Suckless](https://suckless.org/philosophy)
|
||||
- Blocks:
|
||||
- [Clickable](#clickable-blocks)
|
||||
- Loaded asynchronously
|
||||
- [Updates can be externally triggered](#signalling-changes)
|
||||
- Compatible with `i3blocks` scripts
|
||||
|
||||
> Additionally, this build of `dwmblocks` is more optimized and fixes the
|
||||
> flickering of the status bar when scrolling.
|
||||
|
||||
## Why `dwmblocks`?
|
||||
|
||||
In `dwm`, you have to set the status bar through an infinite loop, like so:
|
||||
|
||||
```sh
|
||||
while :; do
|
||||
xsetroot -name "$(date)"
|
||||
sleep 30
|
||||
done
|
||||
```
|
||||
|
||||
This is inefficient when running multiple commands that need to be updated at
|
||||
different frequencies. For example, to display an unread mail count and a clock
|
||||
in the status bar:
|
||||
|
||||
```sh
|
||||
while :; do
|
||||
xsetroot -name "$(mailCount) $(date)"
|
||||
sleep 60
|
||||
done
|
||||
```
|
||||
|
||||
Both are executed at the same rate, which is wasteful. Ideally, the mail
|
||||
counter would be updated every thirty minutes, since there's a limit to the
|
||||
number of requests I can make using Gmail's APIs (as a free user).
|
||||
|
||||
`dwmblocks` allows you to divide the status bar into multiple blocks, each of
|
||||
which can be updated at its own interval. This effectively addresses the
|
||||
previous issue, because the commands in a block are only executed once within
|
||||
that time frame.
|
||||
|
||||
## Why `dwmblocks-async`?
|
||||
|
||||
The magic of `dwmblocks-async` is in the `async` part. Since vanilla
|
||||
`dwmblocks` executes the commands of each block sequentially, it leads to
|
||||
annoying freezes. In cases where one block takes several seconds to execute,
|
||||
like in the mail and date blocks example from above, the delay is clearly
|
||||
visible. Fire up a new instance of `dwmblocks` and you'll see!
|
||||
|
||||
With `dwmblocks-async`, the computer executes each block asynchronously
|
||||
(simultaneously).
|
||||
|
||||
## Installation
|
||||
|
||||
Clone this repository, modify `config.h` appropriately, then compile the
|
||||
program:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/UtkarshVerma/dwmblocks-async.git
|
||||
cd dwmblocks-async
|
||||
vi config.h
|
||||
sudo make install
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
To set `dwmblocks-async` as your status bar, you need to run it as a background
|
||||
process on startup. One way is to add the following to `~/.xinitrc`:
|
||||
|
||||
```sh
|
||||
# The binary of `dwmblocks-async` is named `dwmblocks`
|
||||
dwmblocks &
|
||||
```
|
||||
|
||||
### Modifying the blocks
|
||||
|
||||
You can define your status bar blocks in `config.c`:
|
||||
|
||||
```c
|
||||
Block blocks[] = {
|
||||
...
|
||||
{"volume", 0, 5},
|
||||
{"date", 1800, 1},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Each block has the following properties:
|
||||
|
||||
| Property | Description |
|
||||
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Command | The command you wish to execute in your block. |
|
||||
| Update interval | Time in seconds, after which you want the block to update. If `0`, the block will never be updated. |
|
||||
| Update signal | Signal to be used for triggering the block. Must be a positive integer. If `0`, a signal won't be set up for the block and it will be unclickable. |
|
||||
|
||||
Apart from defining the blocks, features can be toggled through `config.h`:
|
||||
|
||||
```c
|
||||
// Maximum possible length of output from block, expressed in number of characters.
|
||||
#define CMDLENGTH 50
|
||||
|
||||
// The status bar's delimiter that appears in between each block.
|
||||
#define DELIMITER " "
|
||||
|
||||
// Adds a leading delimiter to the status bar, useful for powerline.
|
||||
#define LEADING_DELIMITER 1
|
||||
|
||||
// Enable clickability for blocks. See the "Clickable blocks" section below.
|
||||
#define CLICKABLE_BLOCKS 1
|
||||
```
|
||||
|
||||
### Signalling changes
|
||||
|
||||
Most status bars constantly rerun all scripts every few seconds. This is an
|
||||
option here, but a superior choice is to give your block a signal through which
|
||||
you can indicate it to update on relevant event, rather than have it rerun
|
||||
idly.
|
||||
|
||||
For example, the volume block has the update signal `5` by default. I run
|
||||
`kill -39 $(pidof dwmblocks)` alongside my volume shortcuts in `dwm` to only
|
||||
update it when relevant. Just add `34` to your signal number! You could also
|
||||
run `pkill -RTMIN+5 dwmblocks`, but it's slower.
|
||||
|
||||
To refresh all the blocks, run `kill -10 $(pidof dwmblocks)` or
|
||||
`pkill -SIGUSR1 dwmblocks`.
|
||||
|
||||
> All blocks must have different signal numbers!
|
||||
|
||||
### Clickable blocks
|
||||
|
||||
Like `i3blocks`, this build allows you to build in additional actions into your
|
||||
scripts in response to click events. You can check out
|
||||
[my status bar scripts](https://github.com/UtkarshVerma/dotfiles/tree/main/.local/bin/statusbar)
|
||||
as references for using the `$BLOCK_BUTTON` variable.
|
||||
|
||||
To use this feature, define the `CLICKABLE_BLOCKS` feature macro in your
|
||||
`config.h`:
|
||||
|
||||
```c
|
||||
#define CLICKABLE_BLOCKS 1
|
||||
```
|
||||
|
||||
Apart from that, you need `dwm` to be patched with
|
||||
[statuscmd](https://dwm.suckless.org/patches/statuscmd/).
|
||||
|
||||
## Credits
|
||||
|
||||
This work would not have been possible without
|
||||
[Luke's build of dwmblocks](https://github.com/LukeSmithxyz/dwmblocks) and
|
||||
[Daniel Bylinka's statuscmd patch](https://dwm.suckless.org/patches/statuscmd/).
|
15
dwmblocks-async/config.c
Normal file
15
dwmblocks-async/config.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "block.h"
|
||||
#include "util.h"
|
||||
|
||||
Block blocks[] = {
|
||||
{"sb-disk", 1800, 1 },
|
||||
{"sb-memory", 10, 2 },
|
||||
{"sb-loadavg", 5, 3 },
|
||||
{"sb-record", 0, 4 },
|
||||
{"sb-volume", 1, 5 },
|
||||
{"sb-date", 1, 6 },
|
||||
};
|
||||
|
||||
const unsigned short blockCount = LEN(blocks);
|
6
dwmblocks-async/config.h
Normal file
6
dwmblocks-async/config.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#define CLICKABLE_BLOCKS 1 // Enable clickability for blocks
|
||||
#define CMDLENGTH 45 // Trim block output to this length
|
||||
#define DELIMITER " " // Delimiter string used to separate blocks
|
||||
#define LEADING_DELIMITER 0 // Whether a leading separator should be used
|
15
dwmblocks-async/inc/bar.h
Normal file
15
dwmblocks-async/inc/bar.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include "block.h"
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
|
||||
typedef struct {
|
||||
char *current;
|
||||
char *previous;
|
||||
} BarStatus;
|
||||
|
||||
extern unsigned short debugMode;
|
||||
|
||||
void initStatus(BarStatus *);
|
||||
void freeStatus(BarStatus *);
|
||||
void writeStatus(BarStatus *);
|
17
dwmblocks-async/inc/block.h
Normal file
17
dwmblocks-async/inc/block.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
#include "config.h"
|
||||
|
||||
typedef struct {
|
||||
const char *command;
|
||||
const unsigned int interval;
|
||||
const unsigned int signal;
|
||||
int pipe[2];
|
||||
char output[CMDLENGTH * 4 + 1];
|
||||
} Block;
|
||||
|
||||
extern Block blocks[];
|
||||
extern const unsigned short blockCount;
|
||||
|
||||
void execBlock(const Block *, const char *);
|
||||
void execBlocks(unsigned int);
|
||||
void updateBlock(Block *);
|
8
dwmblocks-async/inc/util.h
Normal file
8
dwmblocks-async/inc/util.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#define LEN(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
#define MAX(a, b) (a > b ? a : b)
|
||||
|
||||
int gcd(int, int);
|
||||
void closePipe(int[2]);
|
||||
void trimUTF8(char*, unsigned int);
|
5
dwmblocks-async/inc/x11.h
Normal file
5
dwmblocks-async/inc/x11.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
int setupX();
|
||||
int closeX();
|
||||
void setXRootName(char *);
|
BIN
dwmblocks-async/preview.png
Normal file
BIN
dwmblocks-async/preview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 53 KiB |
62
dwmblocks-async/src/bar.c
Normal file
62
dwmblocks-async/src/bar.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include "bar.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "block.h"
|
||||
#include "x11.h"
|
||||
|
||||
void initStatus(BarStatus *status) {
|
||||
const unsigned int statusLength =
|
||||
(blockCount * (LEN(blocks[0].output) - 1)) +
|
||||
(blockCount - 1 + LEADING_DELIMITER) * (LEN(DELIMITER) - 1);
|
||||
|
||||
status->current = (char *)malloc(statusLength);
|
||||
status->previous = (char *)malloc(statusLength);
|
||||
status->current[0] = '\0';
|
||||
status->previous[0] = '\0';
|
||||
}
|
||||
|
||||
void freeStatus(BarStatus *status) {
|
||||
free(status->current);
|
||||
free(status->previous);
|
||||
}
|
||||
|
||||
int updateStatus(BarStatus *status) {
|
||||
strcpy(status->previous, status->current);
|
||||
status->current[0] = '\0';
|
||||
|
||||
for (int i = 0; i < blockCount; i++) {
|
||||
Block *block = blocks + i;
|
||||
|
||||
if (strlen(block->output)) {
|
||||
#if LEADING_DELIMITER
|
||||
strcat(status->current, DELIMITER);
|
||||
#else
|
||||
if (status->current[0]) strcat(status->current, DELIMITER);
|
||||
#endif
|
||||
|
||||
#if CLICKABLE_BLOCKS
|
||||
if (!debugMode && block->signal) {
|
||||
char signal[] = {block->signal, '\0'};
|
||||
strcat(status->current, signal);
|
||||
}
|
||||
#endif
|
||||
|
||||
strcat(status->current, block->output);
|
||||
}
|
||||
}
|
||||
return strcmp(status->current, status->previous);
|
||||
}
|
||||
|
||||
void writeStatus(BarStatus *status) {
|
||||
// Only write out if status has changed
|
||||
if (!updateStatus(status)) return;
|
||||
|
||||
if (debugMode) {
|
||||
printf("%s\n", status->current);
|
||||
return;
|
||||
}
|
||||
setXRootName(status->current);
|
||||
}
|
72
dwmblocks-async/src/block.c
Normal file
72
dwmblocks-async/src/block.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include "block.h"
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
static int execLock = 0;
|
||||
|
||||
void execBlock(const Block *block, const char *button) {
|
||||
unsigned short i = block - blocks;
|
||||
|
||||
// Ensure only one child process exists per block at an instance
|
||||
if (execLock & 1 << i) return;
|
||||
// Lock execution of block until current instance finishes execution
|
||||
execLock |= 1 << i;
|
||||
|
||||
if (fork() == 0) {
|
||||
close(block->pipe[0]);
|
||||
dup2(block->pipe[1], STDOUT_FILENO);
|
||||
close(block->pipe[1]);
|
||||
|
||||
if (button) setenv("BLOCK_BUTTON", button, 1);
|
||||
|
||||
FILE *file = popen(block->command, "r");
|
||||
if (!file) {
|
||||
printf("\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Buffer will hold both '\n' and '\0'
|
||||
char buffer[LEN(block->output) + 1];
|
||||
if (fgets(buffer, LEN(buffer), file) == NULL) {
|
||||
// Send an empty line in case of no output
|
||||
printf("\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
pclose(file);
|
||||
|
||||
// Trim to the max possible UTF-8 capacity
|
||||
trimUTF8(buffer, LEN(buffer));
|
||||
|
||||
printf("%s\n", buffer);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
void execBlocks(unsigned int time) {
|
||||
for (int i = 0; i < blockCount; i++) {
|
||||
const Block *block = blocks + i;
|
||||
if (time == 0 ||
|
||||
(block->interval != 0 && time % block->interval == 0)) {
|
||||
execBlock(block, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateBlock(Block *block) {
|
||||
char buffer[LEN(block->output)];
|
||||
int bytesRead = read(block->pipe[0], buffer, LEN(buffer));
|
||||
|
||||
// String from pipe will always end with '\n'
|
||||
buffer[bytesRead - 1] = '\0';
|
||||
|
||||
strcpy(block->output, buffer);
|
||||
|
||||
// Remove execution lock for the current block
|
||||
execLock &= ~(1 << (block - blocks));
|
||||
}
|
157
dwmblocks-async/src/main.c
Normal file
157
dwmblocks-async/src/main.c
Normal file
|
@ -0,0 +1,157 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/signalfd.h>
|
||||
|
||||
#include "bar.h"
|
||||
#include "block.h"
|
||||
#include "util.h"
|
||||
#include "x11.h"
|
||||
|
||||
static unsigned short statusContinue = 1;
|
||||
unsigned short debugMode = 0;
|
||||
static int epollFD, signalFD;
|
||||
static unsigned int timerTick = 0, maxInterval = 1;
|
||||
|
||||
void signalHandler() {
|
||||
struct signalfd_siginfo info;
|
||||
read(signalFD, &info, sizeof(info));
|
||||
unsigned int signal = info.ssi_signo;
|
||||
|
||||
static unsigned int timer = 0;
|
||||
switch (signal) {
|
||||
case SIGALRM:
|
||||
// Schedule the next timer event and execute blocks
|
||||
alarm(timerTick);
|
||||
execBlocks(timer);
|
||||
|
||||
// Wrap `timer` to the interval [1, `maxInterval`]
|
||||
timer = (timer + timerTick - 1) % maxInterval + 1;
|
||||
return;
|
||||
case SIGUSR1:
|
||||
// Update all blocks on receiving SIGUSR1
|
||||
execBlocks(0);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int j = 0; j < blockCount; j++) {
|
||||
const Block *block = blocks + j;
|
||||
if (block->signal == signal - SIGRTMIN) {
|
||||
char button[4]; // value can't be more than 255;
|
||||
sprintf(button, "%d", info.ssi_int & 0xff);
|
||||
execBlock(block, button);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void termHandler() {
|
||||
statusContinue = 0;
|
||||
}
|
||||
|
||||
void setupSignals() {
|
||||
sigset_t handledSignals;
|
||||
sigemptyset(&handledSignals);
|
||||
sigaddset(&handledSignals, SIGUSR1);
|
||||
sigaddset(&handledSignals, SIGALRM);
|
||||
|
||||
// Append all block signals to `handledSignals`
|
||||
for (int i = 0; i < blockCount; i++)
|
||||
if (blocks[i].signal > 0)
|
||||
sigaddset(&handledSignals, SIGRTMIN + blocks[i].signal);
|
||||
|
||||
// Create a signal file descriptor for epoll to watch
|
||||
signalFD = signalfd(-1, &handledSignals, 0);
|
||||
|
||||
// Block all realtime and handled signals
|
||||
for (int i = SIGRTMIN; i <= SIGRTMAX; i++) sigaddset(&handledSignals, i);
|
||||
sigprocmask(SIG_BLOCK, &handledSignals, NULL);
|
||||
|
||||
// Handle termination signals
|
||||
signal(SIGINT, termHandler);
|
||||
signal(SIGTERM, termHandler);
|
||||
|
||||
// Avoid zombie subprocesses
|
||||
struct sigaction signalAction;
|
||||
signalAction.sa_handler = SIG_DFL;
|
||||
sigemptyset(&signalAction.sa_mask);
|
||||
signalAction.sa_flags = SA_NOCLDWAIT;
|
||||
sigaction(SIGCHLD, &signalAction, 0);
|
||||
}
|
||||
|
||||
void statusLoop() {
|
||||
// Update all blocks initially
|
||||
raise(SIGALRM);
|
||||
|
||||
BarStatus status;
|
||||
initStatus(&status);
|
||||
struct epoll_event events[blockCount + 1];
|
||||
while (statusContinue) {
|
||||
int eventCount = epoll_wait(epollFD, events, LEN(events), 100);
|
||||
for (int i = 0; i < eventCount; i++) {
|
||||
unsigned short id = events[i].data.u32;
|
||||
if (id < blockCount) {
|
||||
updateBlock(blocks + id);
|
||||
} else {
|
||||
signalHandler();
|
||||
}
|
||||
}
|
||||
|
||||
if (eventCount != -1) writeStatus(&status);
|
||||
}
|
||||
freeStatus(&status);
|
||||
}
|
||||
|
||||
void init() {
|
||||
epollFD = epoll_create(blockCount);
|
||||
struct epoll_event event = {
|
||||
.events = EPOLLIN,
|
||||
};
|
||||
|
||||
for (int i = 0; i < blockCount; i++) {
|
||||
// Append each block's pipe's read end to `epollFD`
|
||||
pipe(blocks[i].pipe);
|
||||
event.data.u32 = i;
|
||||
epoll_ctl(epollFD, EPOLL_CTL_ADD, blocks[i].pipe[0], &event);
|
||||
|
||||
// Calculate the max interval and tick size for the timer
|
||||
if (blocks[i].interval) {
|
||||
maxInterval = MAX(blocks[i].interval, maxInterval);
|
||||
timerTick = gcd(blocks[i].interval, timerTick);
|
||||
}
|
||||
}
|
||||
|
||||
setupSignals();
|
||||
|
||||
// Watch signal file descriptor as well
|
||||
event.data.u32 = blockCount;
|
||||
epoll_ctl(epollFD, EPOLL_CTL_ADD, signalFD, &event);
|
||||
}
|
||||
|
||||
int main(const int argc, const char *argv[]) {
|
||||
if (setupX()) {
|
||||
fprintf(stderr, "%s\n", "dwmblocks: Failed to open display");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (!strcmp("-d", argv[i])) {
|
||||
debugMode = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
statusLoop();
|
||||
|
||||
if (closeX())
|
||||
fprintf(stderr, "%s\n", "dwmblocks: Failed to close display");
|
||||
|
||||
close(epollFD);
|
||||
close(signalFD);
|
||||
for (int i = 0; i < blockCount; i++) closePipe(blocks[i].pipe);
|
||||
|
||||
return 0;
|
||||
}
|
41
dwmblocks-async/src/util.c
Normal file
41
dwmblocks-async/src/util.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include "util.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
int gcd(int a, int b) {
|
||||
int temp;
|
||||
while (b > 0) {
|
||||
temp = a % b;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
void closePipe(int pipe[2]) {
|
||||
close(pipe[0]);
|
||||
close(pipe[1]);
|
||||
}
|
||||
|
||||
void trimUTF8(char* buffer, unsigned int size) {
|
||||
int length = (size - 1) / 4;
|
||||
int count = 0, j = 0;
|
||||
char ch = buffer[j];
|
||||
while (ch != '\0' && ch != '\n' && count < length) {
|
||||
// Skip continuation bytes, if any
|
||||
int skip = 1;
|
||||
while ((ch & 0xc0) > 0x80) {
|
||||
ch <<= 1;
|
||||
skip++;
|
||||
}
|
||||
|
||||
j += skip;
|
||||
ch = buffer[j];
|
||||
count++;
|
||||
}
|
||||
|
||||
// Trim trailing newline and spaces
|
||||
buffer[j] = ' ';
|
||||
while (j >= 0 && buffer[j] == ' ') j--;
|
||||
buffer[j + 1] = '\0';
|
||||
}
|
25
dwmblocks-async/src/x11.c
Normal file
25
dwmblocks-async/src/x11.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "x11.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
static Display *display;
|
||||
static Window rootWindow;
|
||||
|
||||
int setupX() {
|
||||
display = XOpenDisplay(NULL);
|
||||
if (!display) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
rootWindow = DefaultRootWindow(display);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int closeX() {
|
||||
return XCloseDisplay(display);
|
||||
}
|
||||
|
||||
void setXRootName(char *str) {
|
||||
XStoreName(display, rootWindow, str);
|
||||
XFlush(display);
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 196 KiB |
BIN
pics/random.png
BIN
pics/random.png
Binary file not shown.
Before Width: | Height: | Size: 396 KiB |
12
scripts/dwmblocks/musicup
Executable file
12
scripts/dwmblocks/musicup
Executable file
|
@ -0,0 +1,12 @@
|
|||
#!/bin/sh
|
||||
# This loop will update the music statusbar module whenever a command changes the
|
||||
# music player's status. mpd and must be running on X's start for this to work.
|
||||
|
||||
{
|
||||
playerctl metadata -F -f "{{title}}{{artist}}{{status}}" &
|
||||
while ! mpc idleloop 2>/dev/null; do
|
||||
sleep 1
|
||||
done
|
||||
} | while read -r _; do
|
||||
pkill -RTMIN+2 "$STATUSBAR"
|
||||
done
|
53
scripts/dwmblocks/sb-battery
Executable file
53
scripts/dwmblocks/sb-battery
Executable file
|
@ -0,0 +1,53 @@
|
|||
#!/bin/sh
|
||||
# Prints all batteries, their percentage remaining and an emoji corresponding
|
||||
# to charge status (🔌 for plugged up, 🔋 for discharging on battery, etc.).
|
||||
|
||||
notify() {
|
||||
notify-send -i battery-good-symbolic \
|
||||
-h string:x-canonical-private-synchronous:battery \
|
||||
"Battery" "$1" -t 4000
|
||||
}
|
||||
|
||||
case "$BLOCK_BUTTON" in
|
||||
1) notify "$(acpi -b | awk -F ': |, ' '{printf "%s\n%s\n", $2, $4}')" ;;
|
||||
6) "$TERMINAL" -e "$EDITOR" "$0" ;;
|
||||
esac
|
||||
|
||||
. sb-theme
|
||||
|
||||
# Loop through all attached batteries and format the info
|
||||
for battery in /sys/class/power_supply/BAT?*; do
|
||||
# If non-first battery, print a space separator.
|
||||
[ -n "${capacity+x}" ] && printf " "
|
||||
|
||||
capacity="$(cat "$battery/capacity" 2>&1)"
|
||||
if [ "$capacity" -gt 90 ]; then
|
||||
status=" "
|
||||
elif [ "$capacity" -gt 60 ]; then
|
||||
status=" "
|
||||
elif [ "$capacity" -gt 40 ]; then
|
||||
status=" "
|
||||
elif [ "$capacity" -gt 10 ]; then
|
||||
status=" "
|
||||
else
|
||||
status=" "
|
||||
fi
|
||||
|
||||
# Sets up the status and capacity
|
||||
case "$(cat "$battery/status" 2>&1)" in
|
||||
Full) status=" " ;;
|
||||
Discharging)
|
||||
if [ "$capacity" -le 20 ]; then
|
||||
status="$status"
|
||||
color=1
|
||||
fi
|
||||
;;
|
||||
Charging) status="$status" ;;
|
||||
"Not charging") status=" " ;;
|
||||
Unknown) status="? $status" ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
|
||||
# Prints the info
|
||||
display "$status$capacity%" "$color"
|
||||
done && echo
|
23
scripts/dwmblocks/sb-date
Executable file
23
scripts/dwmblocks/sb-date
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/sh
|
||||
# Displays the current time in HH:MM:SS (AM|PM)
|
||||
|
||||
notify() {
|
||||
notify-send -i office-calendar-symbolic \
|
||||
-h string:x-canonical-private-synchronous:"$1" "$@"
|
||||
}
|
||||
|
||||
case $BLOCK_BUTTON in
|
||||
1)
|
||||
notify "This Month" "$(cal --color=always |
|
||||
sed "s|..7m|<span color='$(xrdb -get color1)'>|;s|..0m|</span>|")"
|
||||
appointments="$(calcurse -d1 \
|
||||
--format-apt "• <i>%S - %E</i>\n <span foreground='$(xrdb -get color6)'>%m</span>\n" \
|
||||
--format-event "• <span foreground='$(xrdb -get color6)'>%m</span>\n")"
|
||||
[ -n "$appointments" ] && notify "Appointments" "$appointments"
|
||||
;;
|
||||
2) setsid -f "$TERMINAL" -e calcurse ;;
|
||||
6) "$TERMINAL" -e "$EDITOR" "$0" ;;
|
||||
esac
|
||||
|
||||
. sb-theme
|
||||
display " $(date '+%I:%M:%S %p')"
|
16
scripts/dwmblocks/sb-disk
Executable file
16
scripts/dwmblocks/sb-disk
Executable file
|
@ -0,0 +1,16 @@
|
|||
#!/bin/sh
|
||||
# Displays the disk usages of root and home partitions.
|
||||
|
||||
case $BLOCK_BUTTON in
|
||||
6) "$TERMINAL" -e "$EDITOR" "$0" ;;
|
||||
esac
|
||||
|
||||
. sb-theme
|
||||
fetchDiskUsage() {
|
||||
avail=$(df "$1" | awk 'NR==2 {printf "%2.1f", ($4 / 1024 / 1024)}')
|
||||
percentUsed=$(df "$1" | awk -F'[^0-9]*' 'NR==2 {print $5}')
|
||||
[ "$percentUsed" -le 10 ] && color=10
|
||||
display "${avail}G" "$color"
|
||||
}
|
||||
|
||||
echo "$(display ) $(fetchDiskUsage /)$(display "|")$(fetchDiskUsage /home)"
|
13
scripts/dwmblocks/sb-loadavg
Executable file
13
scripts/dwmblocks/sb-loadavg
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/bin/sh
|
||||
# Displays the average CPU load.
|
||||
|
||||
case $BLOCK_BUTTON in
|
||||
6) "$TERMINAL" -e "$EDITOR" "$0" ;;
|
||||
esac
|
||||
|
||||
threshold=5
|
||||
load=$(cut -d' ' -f1 /proc/loadavg)
|
||||
|
||||
. sb-theme
|
||||
[ 1 -eq "$(echo "$load > $threshold" | bc)" ] && color=9
|
||||
display " $load" "$color"
|
34
scripts/dwmblocks/sb-mail
Executable file
34
scripts/dwmblocks/sb-mail
Executable file
|
@ -0,0 +1,34 @@
|
|||
#!/bin/sh
|
||||
# Displays unread mail count for my email addresses.
|
||||
|
||||
# Keep retrying until internet is there
|
||||
while ! wget --spider -q http://example.com; do
|
||||
sleep 10
|
||||
done
|
||||
|
||||
tokens="token.json college_token.json"
|
||||
icons=" : "
|
||||
|
||||
# Display work mail info during work hours only
|
||||
hour="$(date +"%H")"
|
||||
if [ "$(date +"%u")" -lt 6 ] && [ "$hour" -gt 9 ] && [ "$hour" -le 18 ]; then
|
||||
tokens="$tokens work_token.json"
|
||||
icons="$icons: "
|
||||
fi
|
||||
|
||||
counts=""
|
||||
for token in $tokens; do
|
||||
tokenFile="$XDG_CACHE_HOME/qgmail/$token"
|
||||
[ ! -f "$tokenFile" ] && continue
|
||||
|
||||
icon="${icons%%:*}"
|
||||
icons="${icons#*:}"
|
||||
i=$((i + 1))
|
||||
count="$(qgmail --token "$tokenFile" request \
|
||||
users.labels.get me INBOX | jq -r '.messagesUnread // empty')"
|
||||
counts="$counts${count:+"${counts:+" "}$icon$count"}"
|
||||
done
|
||||
|
||||
[ -z "$counts" ] && exit
|
||||
. sb-theme
|
||||
display "$counts"
|
9
scripts/dwmblocks/sb-memory
Executable file
9
scripts/dwmblocks/sb-memory
Executable file
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh
|
||||
# Displays RAM usage.
|
||||
|
||||
case $BLOCK_BUTTON in
|
||||
6) "$TERMINAL" -e "$EDITOR" "$0" ;;
|
||||
esac
|
||||
|
||||
. sb-theme
|
||||
display " $(free --mebi | awk 'NR==2 {printf ("%2.2fGiB\n", ($3 / 1024))}')"
|
7
scripts/dwmblocks/sb-mic
Executable file
7
scripts/dwmblocks/sb-mic
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
# Display an icon if the microphone is muted.
|
||||
|
||||
if pactl get-source-mute @DEFAULT_SOURCE@ | grep -q yes; then
|
||||
. sb-theme
|
||||
display ""
|
||||
fi
|
27
scripts/dwmblocks/sb-music
Executable file
27
scripts/dwmblocks/sb-music
Executable file
|
@ -0,0 +1,27 @@
|
|||
#!/bin/sh
|
||||
# Display currently playing music metadata.
|
||||
|
||||
case "$BLOCK_BUTTON" in
|
||||
1) musicctl prev ;;
|
||||
2) musicctl toggle ;;
|
||||
3) musicctl next ;;
|
||||
4) musicctl seek +5 ;;
|
||||
5) musicctl seek -5 ;;
|
||||
6) terminal -e "$EDITOR" "$0" ;;
|
||||
esac
|
||||
|
||||
set -- --player spotify,mpv,%any
|
||||
icon=""
|
||||
pausedIcon=""
|
||||
if status="$(playerctl "$@" status 2>&1)" && [ "$status" != "Stopped" ]; then
|
||||
[ "$status" = "Paused" ] && icon="$pausedIcon"
|
||||
currentSong="$(playerctl "$@" metadata --format "{{title}} - {{artist}}")"
|
||||
else
|
||||
[ "$(mpc status "%state%")" = "paused" ] && icon="$pausedIcon"
|
||||
currentSong="$(mpc current -f "%title%[ - %artist%]")"
|
||||
fi
|
||||
|
||||
[ -z "$currentSong" ] && exit
|
||||
|
||||
. sb-theme
|
||||
display "$icon $currentSong"
|
7
scripts/dwmblocks/sb-record
Executable file
7
scripts/dwmblocks/sb-record
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
# Displays an indicator during screen records.
|
||||
|
||||
if [ -f /tmp/record ]; then
|
||||
. sb-theme
|
||||
display ""
|
||||
fi
|
32
scripts/dwmblocks/sb-theme
Executable file
32
scripts/dwmblocks/sb-theme
Executable file
|
@ -0,0 +1,32 @@
|
|||
#!/bin/sh
|
||||
# Utility functions for theming statusbar scripts.
|
||||
|
||||
display() {
|
||||
if [ -n "$2" ]; then
|
||||
color="$2"
|
||||
else
|
||||
case "$(basename "$0")" in
|
||||
sb-mail) color=13 ;;
|
||||
sb-music) color=14 ;;
|
||||
sb-disk) color=10 ;;
|
||||
sb-memory) color=15 ;;
|
||||
sb-loadavg) color=11 ;;
|
||||
sb-mic) color=9 ;;
|
||||
sb-record) color=9 ;;
|
||||
sb-volume) color=15 ;;
|
||||
sb-battery) color=14 ;;
|
||||
sb-date) color=12 ;;
|
||||
sb-network) color=9 ;;
|
||||
*) color=15 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
case "$STATUSBAR" in
|
||||
"dwmblocks")
|
||||
echo "^C$color^$1"
|
||||
;;
|
||||
*)
|
||||
echo "$1"
|
||||
;;
|
||||
esac
|
||||
}
|
28
scripts/dwmblocks/sb-volume
Executable file
28
scripts/dwmblocks/sb-volume
Executable file
|
@ -0,0 +1,28 @@
|
|||
#!/bin/sh
|
||||
|
||||
case $BLOCK_BUTTON in
|
||||
1) setsid -f "$TERMINAL" -e pulsemixer ;;
|
||||
2) pamixer -t ;;
|
||||
4) pamixer -i 3 ;;
|
||||
5) pamixer -d 3 ;;
|
||||
6) "$TERMINAL" -e "$EDITOR" "$0" ;;
|
||||
esac
|
||||
|
||||
. sb-theme
|
||||
if [ "$(pamixer --get-mute)" = true ]; then
|
||||
display " " 9
|
||||
exit
|
||||
fi
|
||||
|
||||
vol="$(pamixer --get-volume)"
|
||||
[ $? -ne 0 ] && [ -z "$vol" ] && exit 1
|
||||
|
||||
if [ "$vol" -gt 40 ]; then
|
||||
icon=" "
|
||||
elif [ "$vol" -gt 15 ]; then
|
||||
icon=" "
|
||||
else
|
||||
icon=" "
|
||||
fi
|
||||
|
||||
display "$icon$vol%"
|
5
slock-flexipatch/.gitignore
vendored
Normal file
5
slock-flexipatch/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
slock
|
||||
*.o
|
||||
dwm
|
||||
config.h
|
||||
patches.h
|
24
slock-flexipatch/LICENSE
Normal file
24
slock-flexipatch/LICENSE
Normal file
|
@ -0,0 +1,24 @@
|
|||
MIT/X Consortium License
|
||||
|
||||
© 2015-2016 Markus Teich <markus.teich@stusta.mhn.de>
|
||||
© 2014 Dimitris Papastamos <sin@2f30.org>
|
||||
© 2006-2014 Anselm R Garbe <anselm@garbe.us>
|
||||
© 2014-2016 Laslo Hunhold <dev@frign.de>
|
||||
|
||||
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.
|
65
slock-flexipatch/Makefile
Normal file
65
slock-flexipatch/Makefile
Normal file
|
@ -0,0 +1,65 @@
|
|||
# slock - simple screen locker
|
||||
# See LICENSE file for copyright and license details.
|
||||
|
||||
include config.mk
|
||||
|
||||
SRC = slock.c ${COMPATSRC}
|
||||
OBJ = ${SRC:.c=.o}
|
||||
|
||||
all: options slock
|
||||
|
||||
options:
|
||||
@echo slock build options:
|
||||
@echo "CFLAGS = ${CFLAGS}"
|
||||
@echo "LDFLAGS = ${LDFLAGS}"
|
||||
@echo "CC = ${CC}"
|
||||
|
||||
.c.o:
|
||||
@echo CC $<
|
||||
@${CC} -c ${CFLAGS} $<
|
||||
|
||||
${OBJ}: config.h config.mk arg.h util.h patches.h
|
||||
|
||||
config.h:
|
||||
@echo creating $@ from config.def.h
|
||||
@cp config.def.h $@
|
||||
|
||||
patches.h:
|
||||
@echo creating $@ from patches.def.h
|
||||
@cp patches.def.h $@
|
||||
|
||||
slock: ${OBJ}
|
||||
@echo CC -o $@
|
||||
@${CC} -o $@ ${OBJ} ${LDFLAGS}
|
||||
|
||||
clean:
|
||||
@echo cleaning
|
||||
@rm -f slock ${OBJ} slock-${VERSION}.tar.gz
|
||||
|
||||
dist: clean
|
||||
@echo creating dist tarball
|
||||
@mkdir -p slock-${VERSION}
|
||||
@cp -R LICENSE Makefile README slock.1 config.mk \
|
||||
${SRC} config.def.h arg.h util.h slock-${VERSION}
|
||||
@tar -cf slock-${VERSION}.tar slock-${VERSION}
|
||||
@gzip slock-${VERSION}.tar
|
||||
@rm -rf slock-${VERSION}
|
||||
|
||||
install: all
|
||||
@echo installing executable file to ${DESTDIR}${PREFIX}/bin
|
||||
@mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||
@cp -f slock ${DESTDIR}${PREFIX}/bin
|
||||
@chmod 755 ${DESTDIR}${PREFIX}/bin/slock
|
||||
@chmod u+s ${DESTDIR}${PREFIX}/bin/slock
|
||||
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
|
||||
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
||||
@sed "s/VERSION/${VERSION}/g" <slock.1 >${DESTDIR}${MANPREFIX}/man1/slock.1
|
||||
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/slock.1
|
||||
|
||||
uninstall:
|
||||
@echo removing executable file from ${DESTDIR}${PREFIX}/bin
|
||||
@rm -f ${DESTDIR}${PREFIX}/bin/slock
|
||||
@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
|
||||
@rm -f ${DESTDIR}${MANPREFIX}/man1/slock.1
|
||||
|
||||
.PHONY: all options clean dist install uninstall
|
24
slock-flexipatch/README
Normal file
24
slock-flexipatch/README
Normal file
|
@ -0,0 +1,24 @@
|
|||
slock - simple screen locker
|
||||
============================
|
||||
simple screen locker utility for X.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
In order to build slock you need the Xlib header files.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
Edit config.mk to match your local setup (slock is installed into
|
||||
the /usr/local namespace by default).
|
||||
|
||||
Afterwards enter the following command to build and install slock
|
||||
(if necessary as root):
|
||||
|
||||
make clean install
|
||||
|
||||
|
||||
Running slock
|
||||
-------------
|
||||
Simply invoke the 'slock' command. To get out of it, enter your password.
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue