Add experimental native Wayland support

This commit is contained in:
speedie 2023-06-02 18:37:51 +02:00
parent 7ca66d674f
commit 692e3abc68
63 changed files with 8444 additions and 1444 deletions

2
.gitignore vendored
View file

@ -2,6 +2,8 @@
*.o
*zst*
*sig*
*gz*
*tar*
spmenu
buildconf_dev
buildconf

View file

@ -3,21 +3,43 @@
pkgname=spmenu
pkgver=VERSION
pkgrel=1
pkgdesc="Fancy dynamic menu, compatible with dmenu!"
pkgdesc="Fancy dynamic menu for X11 and Wayland, compatible with dmenu!"
url="https://spmenu.speedie.site"
arch=(i686 x86_64)
license=(MIT)
depends=(sh libxinerama cairo pango libx11 imlib2 fribidi libconfig)
makedepends=(git meson ninja)
depends=(
sh
libxinerama
cairo
pango
wayland
wayland-protocols
libxkbcommon
libx11
imlib2
fribidi
libconfig
)
makedepends=(
git
meson
ninja
)
provides=($pkgname)
conflicts=($pkgname)
source=(
"$pkgname-$pkgver.tar.gz"
"$pkgname-$pkgver.tar.gz.sig"
#"https://ls.speedie.site/releases/$pkgname/$pkgname-$pkgver.tar.gz"
#"https://ls.speedie.site/releases/$pkgname/$pkgname-$pkgver.tar.gz.sig"
)
md5sums=(MD5SUM 'SKIP')
md5sums=(
MD5SUM
'SKIP'
)
build(){
cd $pkgname-$pkgver

View file

@ -174,9 +174,9 @@
</figure>
<h1 id="spmenu">spmenu</h1>
<h2 id="what-is-spmenu">What is spmenu?</h2>
<p>spmenu is an X11 menu application which takes standard input, parses
it, and lets the user choose an option and sends the selected option to
standard output.</p>
<p>spmenu is a simple X11 and Wayland menu application which takes
standard input, parses it, lets the user choose an option and sends the
selected option to standard output.</p>
<p>In addition to this, it also serves as a run launcher through the
included shell script <code>spmenu_run</code>, which handles both $PATH
listing, .desktop entries and file listing.</p>
@ -185,10 +185,28 @@ dmenu, spmenu introduces many new features which can be useful in shell
scripting. There are way too many to list, but spmenu has a <a
href="https://spmenu.speedie.site">wiki</a> which goes through features
in more detail.</p>
<p>It also serves as a dmenu replacement for Wayland users.</p>
<h2 id="dependencies">Dependencies</h2>
<ul>
<li>wayland-client
<ul>
<li>For Wayland support, which is optional.</li>
</ul></li>
<li>wayland-scanner
<ul>
<li>For Wayland support, which is optional.</li>
</ul></li>
<li>wayland-protocols
<ul>
<li>For Wayland support, which is optional.</li>
</ul></li>
<li>xkbcommon
<ul>
<li>For Wayland support, which is optional.</li>
</ul></li>
<li>libX11
<ul>
<li>For X11 support</li>
<li>If youre using macOS, XQuartz is a dependency instead.</li>
<li>If youre using Wayland, <code>xorg-xwayland</code> is a
dependency.</li>
@ -274,10 +292,36 @@ instead.</p>
<p>See <a
href="https://spmenu.speedie.site/index.php/Using+spmenu+on+macOS">this
wiki article</a> for more information.</p>
<h2 id="wayland-support">Wayland support</h2>
<p>Note that Wayland support is still experimental, and some features do
not currently work under Wayland. Some will never work under Wayland due
to limitations. These are:</p>
<ul>
<li>Image support
<ul>
<li>Images simply will not be drawn on Wayland.</li>
<li>Will eventually be solved by replacing imlib2 with cairo.</li>
</ul></li>
<li><code>--x-position</code> and <code>--y-position</code> arguments
<ul>
<li>These arguments do not work under Wayland, because the layer_shell
protocol doesnt allow clients to be placed on a specific position.</li>
</ul></li>
<li>Embedding <code>-w</code> and window manager managed
<code>-wm</code>
<ul>
<li>These arguments do not make much sense on Wayland, and embedding is
not possible due to the original implementation using XEmbed. If the
embed argument is passed it will simply be ignored and the window will
be layered as normal.</li>
</ul></li>
<li><code>--monitor</code> argument</li>
<li>Window borders</li>
<li>Pasting</li>
</ul>
<h2 id="todo">TODO</h2>
<p>Pull requests would be greatly appreciated for any of these
issues!</p>
<h3 id="general">General</h3>
<ul>
<li>Image support: Stop using OpenSSL for caching images, mostly because
MD5() is deprecated as of OpenSSL 3.0, but this would also make it very
@ -290,29 +334,9 @@ easy to have LibreSSL compatibility.</li>
</ul></li>
<li>Matching: Add support for contextual completions similar to
xprompt</li>
<li>Matching: Regex matching
<ul>
<li>Probably use some minimal public domain library for this, Id like
to avoid adding more external dependencies unless its a common
dependency most people already have.</li>
</ul></li>
</ul>
<h3
id="unlikely-but-maybe-at-some-point-in-the-distant-future">Unlikely,
but maybe at some point in the distant future</h3>
<ul>
<li>Matching: Regex matching</li>
<li>X11: Move from Xlib to libXcb</li>
<li>Wayland: Wayland support, but only if it doesnt require writing any
extra code which as of now seems unlikely, or if someone makes a patch.
<ul>
<li>Before this can even be done, deal with keybinds in some Wayland
compatible way, remove .Xresources usage and figure out a way to
preserve X11 compatibility as I do not want to use Wayland as of
now.</li>
<li>You can just use XWayland anyway if you happen to use Wayland, so
its not like you will be unable to use spmenu in its current
state.</li>
</ul></li>
<li>Wayland: Anything listed as broken under Wayland support.</li>
</ul>
<h2 id="scripts">Scripts</h2>
<p>Theres a page dedicated to user scripts <a

View file

@ -5,9 +5,8 @@ spmenu
## What is spmenu?
spmenu is an X11 menu application which takes standard input, parses
it, and lets the user choose an option and sends the
selected option to standard output.
spmenu is a simple X11 and Wayland menu application which takes standard input, parses
it, lets the user choose an option and sends the selected option to standard output.
In addition to this, it also serves as a run launcher through the included
shell script `spmenu_run`, which handles both $PATH listing, .desktop entries
@ -18,9 +17,20 @@ spmenu introduces many new features which can be useful in shell scripting.
There are way too many to list, but spmenu has a
[wiki](https://spmenu.speedie.site) which goes through features in more detail.
It also serves as a dmenu replacement for Wayland users.
## Dependencies
- wayland-client
- For Wayland support, which is optional.
- wayland-scanner
- For Wayland support, which is optional.
- wayland-protocols
- For Wayland support, which is optional.
- xkbcommon
- For Wayland support, which is optional.
- libX11
- For X11 support
- If you're using macOS, XQuartz is a dependency instead.
- If you're using Wayland, `xorg-xwayland` is a dependency.
- libXrender
@ -108,12 +118,30 @@ directory**. If you want to generate a Pacman package, run
See [this wiki article](https://spmenu.speedie.site/index.php/Using+spmenu+on+macOS)
for more information.
## Wayland support
Note that Wayland support is still experimental, and some features do not
currently work under Wayland. Some will never work under Wayland due to limitations.
These are:
- Image support
- Images simply will not be drawn on Wayland.
- Will eventually be solved by replacing imlib2 with cairo.
- `--x-position` and `--y-position` arguments
- These arguments do not work under Wayland, because the layer_shell
protocol doesn't allow clients to be placed on a specific position.
- Embedding `-w` and window manager managed `-wm`
- These arguments do not make much sense on Wayland, and embedding is not possible
due to the original implementation using XEmbed. If the embed argument is passed
it will simply be ignored and the window will be layered as normal.
- `--monitor` argument
- Window borders
- Pasting
## TODO
Pull requests would be greatly appreciated for any of these issues!
### General
- Image support: Stop using OpenSSL for caching images, mostly because MD5()
is deprecated as of OpenSSL 3.0, but this would also make it very easy to
have LibreSSL compatibility.
@ -123,20 +151,8 @@ have LibreSSL compatibility.
for each added line.
- Matching: Add support for contextual completions similar to xprompt
- Matching: Regex matching
- Probably use some minimal public domain library for this, I'd
like to avoid adding more external dependencies unless it's a
common dependency most people already have.
### Unlikely, but maybe at some point in the distant future
- X11: Move from Xlib to libXcb
- Wayland: Wayland support, but only if it doesn't require writing any extra
code which as of now seems unlikely, or if someone makes a patch.
- Before this can even be done, deal with keybinds in some Wayland compatible
way, remove .Xresources usage and figure out a way to preserve X11
compatibility as I do not want to use Wayland as of now.
- You can just use XWayland anyway if you happen to use Wayland, so it's not
like you will be unable to use spmenu in its current state.
- Wayland: Anything listed as broken under 'Wayland support'.
## Scripts

View file

@ -4,7 +4,7 @@
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>spmenu documentation 1.2.1</title>
<title>spmenu documentation 2.0</title>
<style>
html {
color: #1a1a1a;
@ -166,7 +166,7 @@
</head>
<body>
<header id="title-block-header">
<h1 class="title">spmenu documentation 1.2.1</h1>
<h1 class="title">spmenu documentation 2.0</h1>
</header>
<nav id="TOC" role="doc-toc">
<ul>

View file

@ -1,9 +1,8 @@
spmenu
======
spmenu is an X11 menu application which takes standard input, parses
it, and lets the user choose an option and sends the
selected option to standard output.
spmenu is an X11 and Wayland menu application which takes standard input, parses
it, lets the user choose an option and sends the selected option to standard output.
In addition to this, it also serves as a run launcher through the included
shell script `spmenu_run`, which handles both $PATH listing, .desktop entries
@ -13,6 +12,8 @@ using spmenu as a run launcher.
While spmenu is based on dmenu, and is also fully compatible with dmenu,
spmenu introduces many new features which can be useful in shell scripting.
It also serves as a dmenu replacement for Wayland users.
## Usage
On runtime, spmenu reads from standard input (stdin). spmenu items are
@ -54,12 +55,6 @@ You may use long, descriptive arguments or the shorter arguments.
`-cd, --cache-dir dir`
: Set cache directory to dir
`-rw, --relative-width`
: Enable relative input width
`-nrw, --no-relative-width`
: Disable relative input width
`-ix, --print-index`
: Print index instead of actual text
@ -360,6 +355,12 @@ You may use long, descriptive arguments or the shorter arguments.
`-nltm, --no-load-theme`
: Don't load theme (~/.config/spmenu/theme.conf) on runtime
`-x11, --x11`
: Run spmenu in X11 mode
`-wl, --wayland`
: Run spmenu in Wayland mode
`-v, --version`
: Print spmenu version to stdout
@ -756,6 +757,8 @@ These are the default keybinds. You can generate these yourself from a
## .Xresources
**NOTE: Only applies for X11 users**
spmenu also has .Xresources (xrdb) support built in. It reads the xrdb
(.Xresources database) on runtime. You may disable it by passing -nxrdb,
or enable it by padding -xrdb. You can also set this in the config file.
@ -825,6 +828,26 @@ run `printf 'spmenu:version' | spmenu`. There are a few of these.
`spmenu:license`
: Print the spmenu license
## Wayland support
Note that Wayland support is still experimental, and some features do not
currently work under Wayland. Some will never work under Wayland due to limitations.
These are:
- Image support
- Images simply will not be drawn on Wayland.
- Will eventually be solved by replacing imlib2 with cairo.
- `--x-position` and `--y-position` arguments
- These arguments do not work under Wayland, because the layer_shell
protocol doesn't allow clients to be placed on a specific position.
- Embedding `-w` and window manager managed `-wm`
- These arguments do not make much sense on Wayland, and embedding is not possible
due to the original implementation using XEmbed. If the embed argument is passed
it will simply be ignored and the window will be layered as normal.
- `--monitor` argument
- Window borders
- Pasting
## License
spmenu is licensed under the MIT license because that's the original suckless

View file

@ -141,7 +141,6 @@ spmenu.menumarginh: 0
spmenu.xpos: 0
spmenu.ypos: 0
spmenu.minwidth: 1000
spmenu.accuratewidth: 0
spmenu.borderwidth: 0
!! Properties

View file

@ -21,6 +21,7 @@ spmenu = {
monitor = -1; // Monitor to spawn spmenu on, (-1, 0, 1, ...)
managed = 0; // Allow your window manager to manage spmenu as a window (0/1)
alpha = 1; // Enable alpha/transparency (0/1)
protocol = 1; // Protocol to attempt to use by default (0: X11, 1: Wayland)
} );
/* X11 properties */
@ -167,7 +168,6 @@ spmenu = {
fuzzy = 1; // Enable fuzzy finding (0/1)
preselected = 0; // Preselect an item, 0 is the first item (number)
mark = 1; // Allow marking/selecting multiple items (0/1)
accuratewidth = 0; // Enable accurate width, could be noticeably slower in some cases (0/1)
delimiters = " "; // Word delimiter, used to delete words (text)
listfile = "NULL"; // File to read entries from. If set to NULL standard input is read. This is read every time a key is pressed. (text)
} );
@ -241,35 +241,30 @@ spmenu = {
*/
mouse = ( // Left click on input: Clear the input
{ click = "ClickInput";
modifier = "None";
button = "Left Click";
function = "clear";
argument = "0";
},
// Left click on prompt: Clear the input
{ click = "ClickPrompt";
modifier = "None";
button = "Left Click";
function = "clear";
argument = "0";
},
// Left click on the mode indicator: Toggle mode
{ click = "ClickMode";
modifier = "None";
button = "Left Click";
function = "switchmode";
argument = "0";
},
// Click on the match count: Toggle viewing history buffer
{ click = "ClickNumber";
modifier = "None";
button = "Left Click";
function = "viewhist";
argument = "0";
},
// Left click on an item: Select it
{ click = "ClickSelItem";
modifier = "None";
button = "Left Click";
function = "None";
argument = "0";

View file

@ -5,6 +5,7 @@
* See LICENSE file for copyright and license details.
*/
/* X11 hardcoded keybinds */
static Key keys[] = {
/* mode modifier key function argument
*
@ -78,3 +79,80 @@ static Key keys[] = {
/* insert mode */
{ 1, 0, XK_Escape, switchmode, {0} },
};
/* Wayland hardcoded keybinds */
#if USEWAYLAND
static WlKey wl_keys[] = {
/* mode modifier key function argument
*
* any mode
*/
{ -1, WL_None, XKB_KEY_Return, selectitem, {.i = +1 } },
{ -1, WL_Shift, XKB_KEY_Return, selectitem, {0} },
{ -1, WL_Ctrl, XKB_KEY_Return, markitem, {0} },
{ -1, WL_None, XKB_KEY_Tab, complete, {0} },
{ -1, WL_Ctrl, XKB_KEY_v, paste, {.i = 2 } },
{ -1, WL_CtrlShift, XKB_KEY_v, paste, {.i = 1 } },
{ -1, WL_None, XKB_KEY_BackSpace, backspace, {0} },
{ -1, WL_Ctrl, XKB_KEY_BackSpace, deleteword, {0} },
{ -1, WL_Ctrl, XKB_KEY_Left, moveword, {.i = -1 } },
{ -1, WL_Ctrl, XKB_KEY_Right, moveword, {.i = +1 } },
{ -1, WL_None, XKB_KEY_Left, movecursor, {.i = -1 } },
{ -1, WL_None, XKB_KEY_Right, movecursor, {.i = +1 } },
{ -1, WL_CtrlShift, XKB_KEY_p, setprofile, {0} },
/* normal mode */
{ 0, WL_None, XKB_KEY_i, switchmode, {0} },
{ 0, WL_None, XKB_KEY_slash, switchmode, {0} },
{ 0, WL_Ctrl, XKB_KEY_equal, setimgsize, {.i = +1 } },
{ 0, WL_Ctrl, XKB_KEY_minus, setimgsize, {.i = -1 } },
{ 0, WL_None, XKB_KEY_equal, setimgsize, {.i = +10 } },
{ 0, WL_None, XKB_KEY_minus, setimgsize, {.i = -10 } },
{ 0, WL_Shift, XKB_KEY_equal, setimgsize, {.i = +100 } },
{ 0, WL_Shift, XKB_KEY_minus, setimgsize, {.i = -100 } },
{ 0, WL_Shift, XKB_KEY_0, defaultimg, {0} },
{ 0, WL_None, XKB_KEY_r, rotateimg, {0} },
{ 0, WL_None, XKB_KEY_o, setimgpos, {.i = +1 } },
{ 0, WL_Ctrl, XKB_KEY_1, setimggaps, {.i = -1 } },
{ 0, WL_Ctrl, XKB_KEY_2, setimggaps, {.i = +1 } },
{ 0, WL_None, XKB_KEY_1, setimggaps, {.i = -10 } },
{ 0, WL_None, XKB_KEY_2, setimggaps, {.i = +10 } },
{ 0, WL_Shift, XKB_KEY_1, setimggaps, {.i = -100 } },
{ 0, WL_Shift, XKB_KEY_2, setimggaps, {.i = +100 } },
{ 0, WL_None, XKB_KEY_t, toggleimg, {0} },
{ 0, WL_None, XKB_KEY_f, togglefullimg, {0} },
{ 0, WL_None, XKB_KEY_p, paste, {.i = 2 } },
{ 0, WL_None, XKB_KEY_h, flipimg, {.i = 1 } },
{ 0, WL_None, XKB_KEY_v, flipimg, {.i = 0 } },
{ 0, WL_None, XKB_KEY_k, moveup, {0} },
{ 0, WL_None, XKB_KEY_j, movedown, {0} },
{ 0, WL_None, XKB_KEY_h, moveleft, {0} },
{ 0, WL_None, XKB_KEY_l, moveright, {0} },
{ 0, WL_Ctrl, XKB_KEY_u, moveup, {.i = 5 } },
{ 0, WL_Ctrl, XKB_KEY_d, movedown, {.i = 5 } },
{ 0, WL_Ctrl, XKB_KEY_k, setlines, {.i = +1 } },
{ 0, WL_Ctrl, XKB_KEY_j, setlines, {.i = -1 } },
{ 0, WL_CtrlAltShift, XKB_KEY_k, setlines, {.i = +5 } },
{ 0, WL_CtrlAltShift, XKB_KEY_j, setlines, {.i = -5 } },
{ 0, WL_Ctrl, XKB_KEY_h, setcolumns, {.i = +1 } },
{ 0, WL_Ctrl, XKB_KEY_l, setcolumns, {.i = -1 } },
{ 0, WL_CtrlAltShift, XKB_KEY_h, setcolumns, {.i = +5 } },
{ 0, WL_CtrlAltShift, XKB_KEY_l, setcolumns, {.i = -5 } },
{ 0, WL_None, XKB_KEY_u, togglehighlight, {0} },
{ 0, WL_CtrlShift, XKB_KEY_h, viewhist, {0} },
{ 0, WL_None, XKB_KEY_d, clear, {0} },
{ 0, WL_Shift, XKB_KEY_d, clearins, {0} },
{ 0, WL_None, XKB_KEY_Escape, quit, {0} },
{ 0, WL_None, XKB_KEY_Home, movestart, {0} },
{ 0, WL_None, XKB_KEY_End, moveend, {0} },
{ 0, WL_None, XKB_KEY_g, movestart, {0} },
{ 0, WL_Shift, XKB_KEY_g, moveend, {0} },
{ 0, WL_None, XKB_KEY_Next, movenext, {0} },
{ 0, WL_None, XKB_KEY_Prior, moveprev, {0} },
{ 0, WL_Alt, XKB_KEY_p, navhistory, {.i = -1 } },
{ 0, WL_Alt, XKB_KEY_n, navhistory, {.i = +1 } },
/* insert mode */
{ 1, WL_None, XKB_KEY_Escape, switchmode, {0} },
};
#endif

View file

@ -159,8 +159,10 @@ void moveend(Arg *arg) {
}
void paste(Arg *arg) {
if (!protocol) {
paste_x11(arg->i);
}
}
void viewhist(Arg *arg) {
int i;
@ -480,6 +482,7 @@ void setlines(Arg *arg) {
}
resizeclient();
calcoffsets();
drawmenu();
}
@ -497,6 +500,7 @@ void setcolumns(Arg *arg) {
}
resizeclient();
calcoffsets();
drawmenu();
}

View file

@ -19,6 +19,10 @@ void readargs(int argc, char *argv[]) {
loadbinds = 1;
} else if (!strcmp(argv[j], "-nlbi") || (!strcmp(argv[j], "--no-load-binds"))) {
loadbinds = 0;
} else if (!strcmp(argv[j], "-x11") || (!strcmp(argv[j], "--x11"))) {
protocol = 0;
} else if (!strcmp(argv[j], "-wl") || (!strcmp(argv[j], "--wayland"))) {
protocol = 1;
#if USECONFIG
} else if (!strcmp(argv[j], "-cf") || (!strcmp(argv[j], "--config-file"))) { // specify a config file
if (argv[j+1]) {
@ -59,7 +63,7 @@ void readargs(int argc, char *argv[]) {
}
// init/read xrdb
if (xresources) {
if (xresources && !protocol) {
#if USEXRESOURCES
XrmInitialize();
load_xresources();
@ -110,10 +114,6 @@ void readargs(int argc, char *argv[]) {
mark = 1;
} else if (!strcmp(argv[i], "-nma") || (!strcmp(argv[i], "--no-mark-items"))) { // don't allow marking items
mark = 0;
} else if (!strcmp(argv[i], "-rw") || (!strcmp(argv[i], "--relative-width"))) { // relative width
accuratewidth = 1;
} else if (!strcmp(argv[i], "-nrw") || (!strcmp(argv[i], "--no-relative-width"))) { // no relative width
accuratewidth = 0;
} else if (!strcmp(argv[i], "-F") || (!strcmp(argv[i], "--fuzzy"))) { // fuzzy matching
fuzzy = 1;
} else if (!strcmp(argv[i], "-NF") || (!strcmp(argv[i], "--no-fuzzy"))) { // no fuzzy matching
@ -226,6 +226,10 @@ void readargs(int argc, char *argv[]) {
|| !strcmp(argv[i], "--no-load-theme")
|| !strcmp(argv[i], "-lbi")
|| !strcmp(argv[i], "-nlbi")
|| !strcmp(argv[i], "-wl")
|| !strcmp(argv[i], "--wayland")
|| !strcmp(argv[i], "-x11")
|| !strcmp(argv[i], "--x11")
|| !strcmp(argv[i], "--load-binds")
|| !strcmp(argv[i], "--no-load-binds")
|| !strcmp(argv[i], "-gbc")
@ -321,27 +325,29 @@ void readargs(int argc, char *argv[]) {
// dmenu compatibility options
} else if (!strcmp(argv[i], "-nb")) { // normal background color
colors[SchemeItemNorm1][ColBg] = argv[++i];
colors[SchemeItemNorm2][ColBg] = argv[++i];
colors[SchemeMenu][ColBg] = argv[++i];
colors[SchemeInput][ColBg] = argv[++i];
colors[SchemePrompt][ColBg] = argv[++i];
int ix = ++i;
strcpy(col_itemnormbg, argv[ix]);
strcpy(col_itemnormbg2, argv[ix]);
strcpy(col_menu, argv[ix]);
strcpy(col_inputbg, argv[ix]);
strcpy(col_promptbg, argv[ix]);
} else if (!strcmp(argv[i], "-nf")) { // normal foreground color
colors[SchemeItemNorm1][ColFg] = argv[++i];
colors[SchemeItemNorm2][ColFg] = argv[++i];
colors[SchemeMenu][ColFg] = argv[++i];
colors[SchemeInput][ColFg] = argv[++i];
colors[SchemePrompt][ColFg] = argv[++i];
int ix = ++i;
strcpy(col_itemnormfg, argv[ix]);
strcpy(col_itemnormfg2, argv[ix]);
strcpy(col_inputfg, argv[ix]);
strcpy(col_promptfg, argv[ix]);
} else if (!strcmp(argv[i], "-sb")) { // selected background color
colors[SchemeItemSel][ColBg] = argv[++i];
colors[SchemeMenu][ColBg] = argv[++i];
colors[SchemeInput][ColBg] = argv[++i];
colors[SchemePrompt][ColBg] = argv[++i];
int ix = ++i;
strcpy(col_itemselbg, argv[ix]);
strcpy(col_menu, argv[ix]);
strcpy(col_inputbg, argv[ix]);
strcpy(col_promptbg, argv[ix]);
} else if (!strcmp(argv[i], "-sf")) { // selected foreground color
colors[SchemeItemSel][ColFg] = argv[++i];
colors[SchemeMenu][ColFg] = argv[++i];
colors[SchemeInput][ColBg] = argv[++i];
colors[SchemePrompt][ColFg] = argv[++i];
int ix = ++i;
strcpy(col_itemselfg, argv[ix]);
strcpy(col_inputfg, argv[ix]);
strcpy(col_promptfg, argv[ix]);
// more
} else if (!strcmp(argv[i], "-is") || (!strcmp(argv[i], "--image-size"))) { // image size
@ -359,65 +365,65 @@ void readargs(int argc, char *argv[]) {
// spmenu colors
} else if (!strcmp(argv[i], "-nif") || (!strcmp(argv[i], "--normal-item-foreground"))) { // normal item foreground color
colors[SchemeItemNorm1][ColFg] = argv[++i];
strcpy(col_itemnormfg, argv[++i]);
} else if (!strcmp(argv[i], "-nib") || (!strcmp(argv[i], "--normal-item-background"))) { // normal item background color
colors[SchemeItemNorm1][ColBg] = argv[++i];
strcpy(col_itemnormbg, argv[++i]);
} else if (!strcmp(argv[i], "-nnif") || (!strcmp(argv[i], "--normal-next-item-foreground"))) { // normal next item foreground color
colors[SchemeItemNorm2][ColFg] = argv[++i];
strcpy(col_itemnormfg2, argv[++i]);
} else if (!strcmp(argv[i], "-nnib") || (!strcmp(argv[i], "--normal-next-item-background"))) { // normal next item background color
colors[SchemeItemNorm2][ColBg] = argv[++i];
strcpy(col_itemnormbg2, argv[++i]);
} else if (!strcmp(argv[i], "-sif") || (!strcmp(argv[i], "--selected-item-foreground"))) { // selected item foreground color
colors[SchemeItemSel][ColFg] = argv[++i];
strcpy(col_itemselfg, argv[++i]);
} else if (!strcmp(argv[i], "-sib") || (!strcmp(argv[i], "--selected-item-background"))) { // selected item background color
colors[SchemeItemSel][ColBg] = argv[++i];
strcpy(col_itemselbg, argv[++i]);
} else if (!strcmp(argv[i], "-npf") || (!strcmp(argv[i], "--normal-item-priority-foreground"))) { // normal item priority foreground color
colors[SchemeItemNormPri][ColFg] = argv[++i];
strcpy(col_itemnormprifg, argv[++i]);
} else if (!strcmp(argv[i], "-npb") || (!strcmp(argv[i], "--normal-item-priority-background"))) { // normal item priority background color
colors[SchemeItemNormPri][ColBg] = argv[++i];
strcpy(col_itemnormpribg, argv[++i]);
} else if (!strcmp(argv[i], "-spf") || (!strcmp(argv[i], "--selected-item-priority-foreground"))) { // selected item priority foreground color
colors[SchemeItemSelPri][ColFg] = argv[++i];
strcpy(col_itemselprifg, argv[++i]);
} else if (!strcmp(argv[i], "-spb") || (!strcmp(argv[i], "--selected-item-priority-background"))) { // selected item priority background color
colors[SchemeItemSelPri][ColBg] = argv[++i];
strcpy(col_itemselpribg, argv[++i]);
} else if (!strcmp(argv[i], "-mnbg") || (!strcmp(argv[i], "--menu-background"))) { // menu color
colors[SchemeMenu][ColBg] = argv[++i];
strcpy(col_menu, argv[++i]);
} else if (!strcmp(argv[i], "-pfg") || (!strcmp(argv[i], "--prompt-foreground"))) { // prompt fg color
colors[SchemePrompt][ColFg] = argv[++i];
strcpy(col_promptfg, argv[++i]);
} else if (!strcmp(argv[i], "-pbg") || (!strcmp(argv[i], "--prompt-background"))) { // prompt bg color
colors[SchemePrompt][ColBg] = argv[++i];
strcpy(col_promptbg, argv[++i]);
} else if (!strcmp(argv[i], "-ifg") || (!strcmp(argv[i], "--input-foreground"))) { // input fg color
colors[SchemeInput][ColFg] = argv[++i];
strcpy(col_inputfg, argv[++i]);
} else if (!strcmp(argv[i], "-pfg") || (!strcmp(argv[i], "--input-background"))) { // input bg color
colors[SchemeInput][ColBg] = argv[++i];
strcpy(col_inputbg, argv[++i]);
} else if (!strcmp(argv[i], "-nhb") || (!strcmp(argv[i], "--normal-highlight-background"))) { // normal highlight background color
colors[SchemeNormHighlight][ColBg] = argv[++i];
} else if (!strcmp(argv[i], "-shf") || (!strcmp(argv[i], "--normal-highlight-foreground"))) { // normal highlight foreground color
colors[SchemeNormHighlight][ColFg] = argv[++i];
} else if (!strcmp(argv[i], "-nhf") || (!strcmp(argv[i], "--selected-highlight-foreground"))) { // selected highlight foreground color
colors[SchemeSelHighlight][ColFg] = argv[++i];
strcpy(col_hlnormbg, argv[++i]);
} else if (!strcmp(argv[i], "-nhf") || (!strcmp(argv[i], "--normal-highlight-foreground"))) { // normal highlight foreground color
strcpy(col_hlnormfg, argv[++i]);
} else if (!strcmp(argv[i], "-shf") || (!strcmp(argv[i], "--selected-highlight-foreground"))) { // selected highlight foreground color
strcpy(col_hlselfg, argv[++i]);
} else if (!strcmp(argv[i], "-shb") || (!strcmp(argv[i], "--selected-highlight-background"))) { // selected highlight background color
colors[SchemeSelHighlight][ColBg] = argv[++i];
strcpy(col_hlselbg, argv[++i]);
} else if (!strcmp(argv[i], "-nbg") || (!strcmp(argv[i], "--number-background"))) { // numbg
colors[SchemeNumber][ColBg] = argv[++i];
strcpy(col_numbg, argv[++i]);
} else if (!strcmp(argv[i], "-nfg") || (!strcmp(argv[i], "--number-foreground"))) { // numfg
colors[SchemeNumber][ColFg] = argv[++i];
strcpy(col_numfg, argv[++i]);
} else if (!strcmp(argv[i], "-mbg") || (!strcmp(argv[i], "--mode-background"))) { // mode
colors[SchemeMode][ColBg] = argv[++i];
strcpy(col_modebg, argv[++i]);
} else if (!strcmp(argv[i], "-mfg") || (!strcmp(argv[i], "--mode-foreground"))) { // mode
colors[SchemeMode][ColFg] = argv[++i];
strcpy(col_modefg, argv[++i]);
} else if (!strcmp(argv[i], "-laf") || (!strcmp(argv[i], "--left-arrow-foreground"))) { // left arrow fg
colors[SchemeLArrow][ColFg] = argv[++i];
strcpy(col_larrowfg, argv[++i]);
} else if (!strcmp(argv[i], "-raf") || (!strcmp(argv[i], "--right-arrow-foreground"))) { // right arrow fg
colors[SchemeRArrow][ColFg] = argv[++i];
strcpy(col_rarrowfg, argv[++i]);
} else if (!strcmp(argv[i], "-lab") || (!strcmp(argv[i], "--left-arrow-background"))) { // left arrow bg
colors[SchemeLArrow][ColFg] = argv[++i];
strcpy(col_larrowbg, argv[++i]);
} else if (!strcmp(argv[i], "-rab") || (!strcmp(argv[i], "--right-arrow-background"))) { // right arrow bg
colors[SchemeRArrow][ColFg] = argv[++i];
strcpy(col_rarrowbg, argv[++i]);
} else if (!strcmp(argv[i], "-bc") || (!strcmp(argv[i], "--border-background"))) { // border
colors[SchemeBorder][ColBg] = argv[++i];
strcpy(col_border, argv[++i]);
} else if (!strcmp(argv[i], "-cc") || (!strcmp(argv[i], "-cfc")) || (!strcmp(argv[i], "--caret-foreground"))) { // caret color
colors[SchemeCaret][ColFg] = argv[++i];
strcpy(col_caretfg, argv[++i]);
} else if (!strcmp(argv[i], "-cbc") || (!strcmp(argv[i], "--caret-background"))) { // caret color
colors[SchemeCaret][ColBg] = argv[++i];
strcpy(col_caretbg, argv[++i]);
}
// sgr colors
@ -452,6 +458,10 @@ void readargs(int argc, char *argv[]) {
|| !strcmp(argv[i], "--no-load-theme")
|| !strcmp(argv[i], "-lbi")
|| !strcmp(argv[i], "-nlbi")
|| !strcmp(argv[i], "-wl")
|| !strcmp(argv[i], "--wayland")
|| !strcmp(argv[i], "-x11")
|| !strcmp(argv[i], "--x11")
|| !strcmp(argv[i], "--load-binds")
|| !strcmp(argv[i], "--no-load-binds")
|| !strcmp(argv[i], "-gbc")
@ -474,6 +484,10 @@ void readargs(int argc, char *argv[]) {
else
fprintf(stderr, "spmenu: Invalid argument: '%s'\n", argv[i]);
#if !USEWAYLAND
protocol = 0;
#endif
if (casesensitive) {
fstrncmp = strncmp;
fstrstr = strstr;
@ -492,7 +506,9 @@ void readargs(int argc, char *argv[]) {
void usage(int status) {
// print help
fputs("spmenu: fancy dynamic menu\n\n"
fputs("spmenu ", status ? stderr : stdout);
fputs(VERSION, status ? stderr : stdout);
fputs(": fancy dynamic menu\n\n"
"- Arguments -\n"
"spmenu -l, --lines <line> Set line count to stdin\n"
"spmenu -mh, --line-height <height> Set spmenu line height to <height>\n"
@ -502,8 +518,6 @@ void usage(int status) {
"spmenu -ngc, --no-generate-cache Don't generate image cache\n"
"spmenu -mc, --max-cache <size> Set max image cache size to <size>\n"
"spmenu -cd, --cache-dir <dir> Set cache directory to <dir>\n"
"spmenu -rw, --relative-width Enable relative input width\n"
"spmenu -nrw, --no-relative-width Disable relative input width\n"
"spmenu -ix, --print-index Print index instead of actual text\n"
"spmenu -nix, --no-print-index Don't print index instead of actual text\n"
"spmenu -f, --fast Grabs keyboard before reading stdin\n"
@ -612,6 +626,8 @@ void usage(int status) {
"spmenu -tm, --theme <theme> Load theme <theme>\n"
"spmenu -ltm, --load-theme Load theme\n"
"spmenu -nltm, --no-load-theme Don't load theme\n"
"spmenu -x11, --x11 Run spmenu in X11 mode\n"
"spmenu -wl, --wayland Run spmenu in Wayland mode\n"
"spmenu -rv, --raw-version Print spmenu version number to stdout\n"
"spmenu -v, --version Print spmenu version to stdout\n"
"\n", status ? stderr : stdout);

View file

@ -1,51 +1,5 @@
/* See LICENSE file for copyright and license details. */
// alpha array
static unsigned int alphas[][2] = {
// fg bg
[SchemeLArrow] = { 255, 200 },
[SchemeRArrow] = { 255, 200 },
[SchemeItemNorm1] = { 255, 200 },
[SchemeItemNorm2] = { 255, 200 },
[SchemeItemSel] = { 255, 200 },
[SchemeItemNormPri] = { 255, 200 },
[SchemeItemSelPri] = { 255, 200 },
[SchemeItemMarked] = { 255, 200 },
[SchemeMenu] = { 255, 200 },
[SchemeInput] = { 255, 200 },
[SchemePrompt] = { 255, 200 },
[SchemeNormHighlight] = { 255, 200 },
[SchemeSelHighlight] = { 255, 200 },
[SchemeMode] = { 255, 200 },
[SchemeCaret] = { 255, 200 },
[SchemeNumber] = { 255, 200 },
[SchemeBorder] = { 255, 200 },
[SchemeCaps] = { 255, 200 },
};
// colorscheme array
static char *colors[][2] = {
// fg bg
[SchemeLArrow] = { col_larrowfg, col_larrowbg },
[SchemeRArrow] = { col_rarrowfg, col_rarrowbg },
[SchemeItemNorm1] = { col_itemnormfg, col_itemnormbg },
[SchemeItemNorm2] = { col_itemnormfg2, col_itemnormbg2 },
[SchemeItemSel] = { col_itemselfg, col_itemselbg },
[SchemeItemNormPri] = { col_itemnormprifg, col_itemnormpribg },
[SchemeItemSelPri] = { col_itemselprifg, col_itemselpribg },
[SchemeItemMarked] = { col_itemmarkedfg, col_itemmarkedbg },
[SchemeInput] = { col_inputfg, col_inputbg, },
[SchemeMenu] = { NULL, col_menu },
[SchemeCaps] = { col_capsfg, col_capsbg },
[SchemePrompt] = { col_promptfg, col_promptbg },
[SchemeNormHighlight] = { col_hlnormfg, col_hlnormbg },
[SchemeSelHighlight] = { col_hlselfg, col_hlselbg },
[SchemeCaret] = { col_caretfg, col_caretbg },
[SchemeMode] = { col_modefg, col_modebg },
[SchemeNumber] = { col_numfg, col_numbg },
[SchemeBorder] = { NULL, col_border },
};
// sgr color array, first 16 colors are defined in the config, the rest are 256 colors
static char *textcolors[] = {
col_sgr0,
@ -304,3 +258,5 @@ static char *textcolors[] = {
"#e4e4e4",
"#eeeeee",
};
static char *txtcols[256];

View file

@ -9,8 +9,6 @@ void conf_init(void) {
char *home = NULL;
const char *dest;
// don't load configuration
if (loadconfig) {
// get path for configuration file
if (!argconf) {
if (!(xdg_conf = getenv("XDG_CONFIG_HOME"))) {
@ -42,23 +40,24 @@ void conf_init(void) {
// don't bother trying to load if it doesn't exist.
if (access(cfgfile, F_OK) != 0) {
return;
loadconfig = 0;
}
// init config
config_t cfg;
config_init(&cfg);
// attempt to read config file to cfg
if (loadconfig) {
if (!config_read_file(&cfg, cfgfile)) {
// invalid configuration, but let's try to read it anyway
fprintf(stderr, "spmenu: Invalid configuration.\n");
}
}
// load options spmenu.window
config_setting_t *window_setting = config_lookup(&cfg, "spmenu.window");
if (window_setting != NULL) {
if (window_setting != NULL && loadconfig) {
// look up window entries
for (unsigned int i = 0; i < config_setting_length(window_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(window_setting, i);
@ -77,12 +76,13 @@ void conf_init(void) {
config_setting_lookup_int(conf, "managed", &managed); // spmenu.window.managed
config_setting_lookup_int(conf, "monitor", &mon); // spmenu.window.monitor
config_setting_lookup_int(conf, "alpha", &alpha); // spmenu.window.alpha
config_setting_lookup_int(conf, "protocol", &protocol); // spmenu.window.protocol
}
}
// load options spmenu.properties
config_setting_t *prop_setting = config_lookup(&cfg, "spmenu.properties");
if (prop_setting != NULL) {
if (prop_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(prop_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(prop_setting, i);
@ -96,7 +96,7 @@ void conf_init(void) {
// load options spmenu.powerline
config_setting_t *pwl_setting = config_lookup(&cfg, "spmenu.powerline");
if (pwl_setting != NULL) {
if (pwl_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(pwl_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(pwl_setting, i);
@ -114,7 +114,7 @@ void conf_init(void) {
// load options spmenu.center
config_setting_t *center_setting = config_lookup(&cfg, "spmenu.center");
if (center_setting != NULL) {
if (center_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(center_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(center_setting, i);
@ -124,7 +124,7 @@ void conf_init(void) {
// load options spmenu.text
config_setting_t *text_setting = config_lookup(&cfg, "spmenu.text");
if (text_setting != NULL) {
if (text_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(text_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(text_setting, i);
@ -162,7 +162,7 @@ void conf_init(void) {
// load options spmenu.alpha
config_setting_t *alpha_setting = config_lookup(&cfg, "spmenu.alpha");
if (alpha_setting != NULL) {
if (alpha_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(alpha_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(alpha_setting, i);
@ -226,131 +226,131 @@ void conf_init(void) {
// load options spmenu.color
config_setting_t *color_setting = config_lookup(&cfg, "spmenu.color");
if (color_setting != NULL) {
if (color_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(color_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(color_setting, i);
// items
if (config_setting_lookup_string(conf, "itemnormfg", &dest))
strcpy(colors[SchemeItemNorm1][ColFg], strdup(dest));
strcpy(col_itemnormfg, strdup(dest));
if (config_setting_lookup_string(conf, "itemnormbg", &dest))
strcpy(colors[SchemeItemNorm1][ColBg], strdup(dest));
strcpy(col_itemnormbg, strdup(dest));
if (config_setting_lookup_string(conf, "itemnormfg2", &dest))
strcpy(colors[SchemeItemNorm2][ColFg], strdup(dest));
strcpy(col_itemnormfg2, strdup(dest));
else if (config_setting_lookup_string(conf, "itemnormfg", &dest))
strcpy(colors[SchemeItemNorm2][ColBg], strdup(dest));
strcpy(col_itemnormfg2, strdup(dest));
if (config_setting_lookup_string(conf, "itemnormbg2", &dest))
strcpy(colors[SchemeItemNorm2][ColBg], strdup(dest));
strcpy(col_itemnormbg2, strdup(dest));
else if (config_setting_lookup_string(conf, "itemnormbg", &dest))
strcpy(colors[SchemeItemNorm2][ColBg], strdup(dest));
strcpy(col_itemnormbg2, strdup(dest));
if (config_setting_lookup_string(conf, "itemselfg", &dest))
strcpy(colors[SchemeItemSel][ColFg], strdup(dest));
strcpy(col_itemselfg, strdup(dest));
if (config_setting_lookup_string(conf, "itemselbg", &dest))
strcpy(colors[SchemeItemSel][ColBg], strdup(dest));
strcpy(col_itemselbg, strdup(dest));
if (config_setting_lookup_string(conf, "itemmarkedfg", &dest))
strcpy(colors[SchemeItemMarked][ColFg], strdup(dest));
strcpy(col_itemmarkedfg, strdup(dest));
else if (config_setting_lookup_string(conf, "itemselfg", &dest))
strcpy(colors[SchemeItemMarked][ColFg], strdup(dest));
strcpy(col_itemmarkedfg, strdup(dest));
if (config_setting_lookup_string(conf, "itemmarkedbg", &dest))
strcpy(colors[SchemeItemMarked][ColBg], strdup(dest));
strcpy(col_itemmarkedbg, strdup(dest));
else if (config_setting_lookup_string(conf, "itemselbg", &dest))
strcpy(colors[SchemeItemMarked][ColBg], strdup(dest));
strcpy(col_itemmarkedbg, strdup(dest));
// items with priority
if (config_setting_lookup_string(conf, "itemnormprifg", &dest))
strcpy(colors[SchemeItemNormPri][ColFg], strdup(dest));
strcpy(col_itemnormprifg, strdup(dest));
if (config_setting_lookup_string(conf, "itemnormpribg", &dest))
strcpy(colors[SchemeItemNormPri][ColBg], strdup(dest));
strcpy(col_itemnormpribg, strdup(dest));
if (config_setting_lookup_string(conf, "itemselprifg", &dest))
strcpy(colors[SchemeItemSelPri][ColFg], strdup(dest));
strcpy(col_itemselprifg, strdup(dest));
if (config_setting_lookup_string(conf, "itemselpribg", &dest))
strcpy(colors[SchemeItemSelPri][ColBg], strdup(dest));
strcpy(col_itemselpribg, strdup(dest));
// input
if (config_setting_lookup_string(conf, "inputfg", &dest))
strcpy(colors[SchemeInput][ColFg], strdup(dest));
strcpy(col_inputfg, strdup(dest));
if (config_setting_lookup_string(conf, "inputbg", &dest))
strcpy(colors[SchemeInput][ColBg], strdup(dest));
strcpy(col_inputbg, strdup(dest));
// menu
if (config_setting_lookup_string(conf, "menu", &dest))
strcpy(colors[SchemeMenu][ColBg], strdup(dest));
strcpy(col_menu, strdup(dest));
// prompt
if (config_setting_lookup_string(conf, "promptfg", &dest))
strcpy(colors[SchemePrompt][ColFg], strdup(dest));
strcpy(col_promptfg, strdup(dest));
if (config_setting_lookup_string(conf, "promptbg", &dest))
strcpy(colors[SchemePrompt][ColBg], strdup(dest));
strcpy(col_promptbg, strdup(dest));
// arrows
if (config_setting_lookup_string(conf, "larrowfg", &dest))
strcpy(colors[SchemeLArrow][ColFg], strdup(dest));
strcpy(col_larrowfg, strdup(dest));
if (config_setting_lookup_string(conf, "larrowbg", &dest))
strcpy(colors[SchemeLArrow][ColBg], strdup(dest));
strcpy(col_larrowbg, strdup(dest));
if (config_setting_lookup_string(conf, "rarrowfg", &dest))
strcpy(colors[SchemeRArrow][ColFg], strdup(dest));
strcpy(col_rarrowfg, strdup(dest));
if (config_setting_lookup_string(conf, "rarrowbg", &dest))
strcpy(colors[SchemeRArrow][ColBg], strdup(dest));
strcpy(col_rarrowbg, strdup(dest));
// highlight
if (config_setting_lookup_string(conf, "hlnormfg", &dest))
strcpy(colors[SchemeNormHighlight][ColFg], strdup(dest));
strcpy(col_hlnormfg, strdup(dest));
if (config_setting_lookup_string(conf, "hlnormbg", &dest))
strcpy(colors[SchemeNormHighlight][ColBg], strdup(dest));
strcpy(col_hlnormbg, strdup(dest));
if (config_setting_lookup_string(conf, "hlselfg", &dest))
strcpy(colors[SchemeSelHighlight][ColFg], strdup(dest));
strcpy(col_hlselfg, strdup(dest));
if (config_setting_lookup_string(conf, "hlselbg", &dest))
strcpy(colors[SchemeSelHighlight][ColBg], strdup(dest));
strcpy(col_hlselbg, strdup(dest));
// number
if (config_setting_lookup_string(conf, "numfg", &dest))
strcpy(colors[SchemeNumber][ColFg], strdup(dest));
strcpy(col_numfg, strdup(dest));
if (config_setting_lookup_string(conf, "numbg", &dest))
strcpy(colors[SchemeNumber][ColBg], strdup(dest));
strcpy(col_numbg, strdup(dest));
// mode
if (config_setting_lookup_string(conf, "modefg", &dest))
strcpy(colors[SchemeMode][ColFg], strdup(dest));
strcpy(col_modefg, strdup(dest));
if (config_setting_lookup_string(conf, "modebg", &dest))
strcpy(colors[SchemeMode][ColBg], strdup(dest));
strcpy(col_modebg, strdup(dest));
// caps
if (config_setting_lookup_string(conf, "capsfg", &dest))
strcpy(colors[SchemeCaps][ColFg], strdup(dest));
strcpy(col_capsfg, strdup(dest));
if (config_setting_lookup_string(conf, "capsbg", &dest))
strcpy(colors[SchemeCaps][ColBg], strdup(dest));
strcpy(col_capsbg, strdup(dest));
// border
if (config_setting_lookup_string(conf, "border", &dest))
strcpy(colors[SchemeBorder][ColBg], strdup(dest));
strcpy(col_border, strdup(dest));
// caret
if (config_setting_lookup_string(conf, "caretfg", &dest))
strcpy(colors[SchemeCaret][ColFg], strdup(dest));
strcpy(col_caretfg, strdup(dest));
if (config_setting_lookup_string(conf, "caretbg", &dest))
strcpy(colors[SchemeCaret][ColBg], strdup(dest));
strcpy(col_caretbg, strdup(dest));
// sgr colors
if (config_setting_lookup_string(conf, "sgr0", &dest))
@ -394,7 +394,7 @@ void conf_init(void) {
// load options spmenu.image
config_setting_t *img_setting = config_lookup(&cfg, "spmenu.image");
if (img_setting != NULL) {
if (img_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(img_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(img_setting, i);
@ -412,7 +412,7 @@ void conf_init(void) {
// load options spmenu.file
config_setting_t *file_setting = config_lookup(&cfg, "spmenu.file");
if (file_setting != NULL) {
if (file_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(file_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(file_setting, i);
@ -426,7 +426,7 @@ void conf_init(void) {
// load options spmenu.input
config_setting_t *input_setting = config_lookup(&cfg, "spmenu.input");
if (input_setting != NULL) {
if (input_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(input_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(input_setting, i);
@ -439,7 +439,7 @@ void conf_init(void) {
// load options spmenu.output
config_setting_t *output_setting = config_lookup(&cfg, "spmenu.output");
if (output_setting != NULL) {
if (output_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(output_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(output_setting, i);
@ -451,7 +451,7 @@ void conf_init(void) {
// load options spmenu.mode
config_setting_t *mode_setting = config_lookup(&cfg, "spmenu.mode");
if (mode_setting != NULL) {
if (mode_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(mode_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(mode_setting, i);
@ -468,7 +468,7 @@ void conf_init(void) {
// load options spmenu.match
config_setting_t *match_setting = config_lookup(&cfg, "spmenu.match");
if (match_setting != NULL) {
if (match_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(match_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(match_setting, i);
@ -478,7 +478,6 @@ void conf_init(void) {
config_setting_lookup_int(conf, "fuzzy", &fuzzy); // spmenu.match.fuzzy
config_setting_lookup_int(conf, "preselected", &preselected); // spmenu.match.preselected
config_setting_lookup_int(conf, "mark", &mark); // spmenu.match.mark
config_setting_lookup_int(conf, "accuratewidth", &accuratewidth); // spmenu.match.accuratewidth
config_setting_lookup_string(conf, "delimiters", &dest); // spmenu.match.delimiters
worddelimiters = strdup(dest);
if (config_setting_lookup_string(conf, "listfile", &dest)) // spmenu.match.listfile
@ -489,7 +488,7 @@ void conf_init(void) {
// load options spmenu.line
config_setting_t *line_setting = config_lookup(&cfg, "spmenu.line");
if (line_setting != NULL) {
if (line_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(line_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(line_setting, i);
@ -503,7 +502,7 @@ void conf_init(void) {
// load options spmenu.history
config_setting_t *hist_setting = config_lookup(&cfg, "spmenu.history");
if (hist_setting != NULL) {
if (hist_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(hist_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(hist_setting, i);
@ -515,7 +514,7 @@ void conf_init(void) {
// load options spmenu.hide
config_setting_t *hide_setting = config_lookup(&cfg, "spmenu.hide");
if (hide_setting != NULL) {
if (hide_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(hide_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(hide_setting, i);
@ -537,7 +536,7 @@ void conf_init(void) {
// load options spmenu.pango
config_setting_t *pango_setting = config_lookup(&cfg, "spmenu.pango");
if (pango_setting != NULL) {
if (pango_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(pango_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(pango_setting, i);
@ -557,7 +556,7 @@ void conf_init(void) {
// load options spmenu.keys
config_setting_t *key_setting = config_lookup(&cfg, "spmenu.keys");
if (key_setting != NULL) {
if (key_setting != NULL && loadconfig) {
int nmode = 0;
for (unsigned int i = 0; i < config_setting_length(key_setting); ++i) {
@ -572,8 +571,19 @@ void conf_init(void) {
}
}
#if USEWAYLAND
for (int j = 0; j < LENGTH(wml); j++) {
if (!strcmp(wml[j].mod, strdup(dest))) {
wl_ckeys[i].modifier = wml[j].modifier;
}
}
#endif
if (config_setting_lookup_int(conf, "mode", &nmode)) {
ckeys[i].mode = nmode;
#if USEWAYLAND
wl_ckeys[i].mode = nmode;
#endif
}
config_setting_lookup_string(conf, "key", &dest);
@ -584,11 +594,22 @@ void conf_init(void) {
}
}
#if USEWAYLAND
for (int j = 0; j < LENGTH(wkl); j++) {
if (!strcmp(wkl[j].key, strdup(dest))) {
wl_ckeys[i].keysym = wkl[j].keysym;
}
}
#endif
config_setting_lookup_string(conf, "function", &dest);
for (int j = 0; j < LENGTH(fl); j++) {
if (!strcmp(fl[j].function, strdup(dest))) {
ckeys[i].func = fl[j].func;
#if USEWAYLAND
wl_ckeys[i].func = fl[j].func;
#endif
}
}
@ -597,6 +618,9 @@ void conf_init(void) {
for (int j = 0; j < LENGTH(al); j++) {
if (!strcmp(al[j].argument, strdup(dest))) {
ckeys[i].arg = al[j].arg;
#if USEWAYLAND
wl_ckeys[i].arg = al[j].arg;
#endif
}
}
@ -606,22 +630,18 @@ void conf_init(void) {
// load options spmenu.mouse
config_setting_t *mouse_setting = config_lookup(&cfg, "spmenu.mouse");
if (mouse_setting != NULL) {
if (mouse_setting != NULL && loadconfig) {
for (unsigned int i = 0; i < config_setting_length(mouse_setting); ++i) {
config_setting_t *conf = config_setting_get_elem(mouse_setting, i);
config_setting_lookup_string(conf, "click", &dest);
for (int j = 0; j < LENGTH(ctp); j++) {
if (!strcmp(ctp[j].tclick, strdup(dest))) {
cbuttons[i].click = ctp[j].click;
}
}
// look up
config_setting_lookup_string(conf, "modifier", &dest);
for (int j = 0; j < LENGTH(ml); j++) {
if (!strcmp(ml[j].mod, strdup(dest))) {
cbuttons[i].mask = ml[j].modifier;
#if USEWAYLAND
wl_cbuttons[i].click = ctp[j].click;
#endif
}
}
@ -633,11 +653,22 @@ void conf_init(void) {
}
}
#if USEWAYLAND
for (int j = 0; j < LENGTH(w_btp); j++) {
if (!strcmp(w_btp[j].click, strdup(dest))) {
wl_cbuttons[i].button = w_btp[j].button;
}
}
#endif
config_setting_lookup_string(conf, "function", &dest);
for (int j = 0; j < LENGTH(fl); j++) {
if (!strcmp(fl[j].function, strdup(dest))) {
cbuttons[i].func = fl[j].func;
#if USEWAYLAND
wl_cbuttons[i].func = fl[j].func;
#endif
}
}
@ -646,6 +677,9 @@ void conf_init(void) {
for (int j = 0; j < LENGTH(al); j++) {
if (!strcmp(al[j].argument, strdup(dest))) {
cbuttons[i].arg = al[j].arg;
#if USEWAYLAND
wl_cbuttons[i].arg = al[j].arg;
#endif
}
}
@ -655,14 +689,12 @@ void conf_init(void) {
// we're done with this config
config_destroy(&cfg);
}
// load the theme now
if (loadtheme) {
theme_load();
}
if (loadbinds) {
if (!argbinds) {
if (!(xdg_conf = getenv("XDG_CONFIG_HOME"))) {
home = getenv("HOME");
@ -705,10 +737,13 @@ void conf_init(void) {
// load options binds.keys
config_setting_t *key_bind = config_lookup(&bind, "bind.keys");
if (key_bind != NULL) {
if (key_bind != NULL && loadbinds) {
int nmode = 0;
memset(ckeys, '\0', LENGTH(ckeys)-1);
#if USEWAYLAND
memset(wl_ckeys, '\0', LENGTH(wl_ckeys)-1);
#endif
for (unsigned int i = 0; i < config_setting_length(key_bind); ++i) {
config_setting_t *conf = config_setting_get_elem(key_bind, i);
@ -721,8 +756,19 @@ void conf_init(void) {
}
}
#if USEWAYLAND
for (int j = 0; j < LENGTH(wml); j++) {
if (!strcmp(wml[j].mod, strdup(dest))) {
wl_ckeys[i].modifier = wml[j].modifier;
}
}
#endif
if (config_setting_lookup_int(conf, "mode", &nmode)) {
ckeys[i].mode = nmode;
#if USEWAYLAND
wl_ckeys[i].mode = nmode;
#endif
}
config_setting_lookup_string(conf, "key", &dest);
@ -733,11 +779,22 @@ void conf_init(void) {
}
}
#if USEWAYLAND
for (int j = 0; j < LENGTH(wkl); j++) {
if (!strcmp(wkl[j].key, strdup(dest))) {
wl_ckeys[i].keysym = wkl[j].keysym;
}
}
#endif
config_setting_lookup_string(conf, "function", &dest);
for (int j = 0; j < LENGTH(fl); j++) {
if (!strcmp(fl[j].function, strdup(dest))) {
ckeys[i].func = fl[j].func;
#if USEWAYLAND
wl_ckeys[i].func = fl[j].func;
#endif
}
}
@ -746,6 +803,9 @@ void conf_init(void) {
for (int j = 0; j < LENGTH(al); j++) {
if (!strcmp(al[j].argument, strdup(dest))) {
ckeys[i].arg = al[j].arg;
#if USEWAYLAND
wl_ckeys[i].arg = al[j].arg;
#endif
}
}
@ -755,26 +815,19 @@ void conf_init(void) {
// load options binds.mouse
config_setting_t *mouse_bind = config_lookup(&bind, "bind.mouse");
if (mouse_bind != NULL) {
if (mouse_bind != NULL && loadbinds) {
memset(cbuttons, '\0', LENGTH(cbuttons)-1);
for (unsigned int i = 0; i < config_setting_length(mouse_bind); ++i) {
config_setting_t *conf = config_setting_get_elem(mouse_bind, i);
// look up
config_setting_lookup_string(conf, "click", &dest);
for (int j = 0; j < LENGTH(ctp); j++) {
if (!strcmp(ctp[j].tclick, strdup(dest))) {
cbuttons[i].click = ctp[j].click;
}
}
// look up
config_setting_lookup_string(conf, "modifier", &dest);
for (int j = 0; j < LENGTH(ml); j++) {
if (!strcmp(ml[j].mod, strdup(dest))) {
cbuttons[i].mask = ml[j].modifier;
#if USEWAYLAND
wl_cbuttons[i].click = ctp[j].click;
#endif
}
}
@ -786,11 +839,22 @@ void conf_init(void) {
}
}
#if USEWAYLAND
for (int j = 0; j < LENGTH(w_btp); j++) {
if (!strcmp(w_btp[j].click, strdup(dest))) {
wl_cbuttons[i].button = w_btp[j].button;
}
}
#endif
config_setting_lookup_string(conf, "function", &dest);
for (int j = 0; j < LENGTH(fl); j++) {
if (!strcmp(fl[j].function, strdup(dest))) {
cbuttons[i].func = fl[j].func;
#if USEWAYLAND
wl_cbuttons[i].func = fl[j].func;
#endif
}
}
@ -799,6 +863,9 @@ void conf_init(void) {
for (int j = 0; j < LENGTH(al); j++) {
if (!strcmp(al[j].argument, strdup(dest))) {
cbuttons[i].arg = al[j].arg;
#if USEWAYLAND
wl_cbuttons[i].arg = al[j].arg;
#endif
}
}
@ -808,7 +875,6 @@ void conf_init(void) {
// finally done
config_destroy(&bind);
}
return;
}

View file

@ -6,11 +6,25 @@ typedef struct {
KeySym keysym;
} KeyList;
#if USEWAYLAND
typedef struct {
char *key;
xkb_keysym_t keysym;
} WlKeyList;
#endif
typedef struct {
char *mod;
unsigned int modifier;
} ModList;
#if USEWAYLAND
typedef struct {
char *mod;
char *modifier;
} WlModList;
#endif
typedef struct {
char *argument;
Arg arg;
@ -396,6 +410,25 @@ static ModList ml[] = {
{ "0", 0 },
};
#if USEWAYLAND
static WlModList wml[] = {
{ "Ctrl+Shift", WL_CtrlShift },
{ "Ctrl+Shift+Super", WL_CtrlShiftSuper },
{ "Ctrl+Super", WL_CtrlSuper },
{ "Ctrl+Alt", WL_CtrlAlt },
{ "Ctrl+Alt+Shift", WL_CtrlAltShift },
{ "Ctrl+Alt+Shift+Super", WL_CtrlAltShiftSuper },
{ "Ctrl+Alt+Super", WL_CtrlAltSuper },
{ "Alt+Shift", WL_AltShift },
{ "Shift", WL_Shift },
{ "Ctrl", WL_Ctrl },
{ "Alt", WL_Alt },
{ "Super", WL_Super },
{ "None", WL_None },
{ "0", WL_None },
};
#endif
// list of keys that can be used in the config file
// expand this array if you want more
static KeyList kl[] = {
@ -500,11 +533,124 @@ static KeyList kl[] = {
{ "Prior", XK_Prior },
};
// list of keys that can be used in the config file
// expand this array if you want more
#if USEWAYLAND
static WlKeyList wkl[] = {
{ "None", 0 },
{ "Space", XKB_KEY_space },
{ "Enter", XKB_KEY_Return },
{ "Tab", XKB_KEY_Tab },
{ "a", XKB_KEY_a },
{ "b", XKB_KEY_b },
{ "c", XKB_KEY_c },
{ "d", XKB_KEY_d },
{ "e", XKB_KEY_e },
{ "f", XKB_KEY_f },
{ "g", XKB_KEY_g },
{ "h", XKB_KEY_h },
{ "i", XKB_KEY_i },
{ "j", XKB_KEY_j },
{ "k", XKB_KEY_k },
{ "l", XKB_KEY_l },
{ "m", XKB_KEY_m },
{ "n", XKB_KEY_n },
{ "o", XKB_KEY_o },
{ "p", XKB_KEY_p },
{ "q", XKB_KEY_q },
{ "r", XKB_KEY_r },
{ "s", XKB_KEY_s },
{ "t", XKB_KEY_t },
{ "u", XKB_KEY_u },
{ "v", XKB_KEY_v },
{ "w", XKB_KEY_w },
{ "x", XKB_KEY_x },
{ "y", XKB_KEY_y },
{ "z", XKB_KEY_z },
{ "0", XKB_KEY_0 },
{ "1", XKB_KEY_1 },
{ "2", XKB_KEY_2 },
{ "3", XKB_KEY_3 },
{ "4", XKB_KEY_4 },
{ "5", XKB_KEY_5 },
{ "6", XKB_KEY_6 },
{ "7", XKB_KEY_7 },
{ "8", XKB_KEY_8 },
{ "9", XKB_KEY_9 },
{ "!", XKB_KEY_exclam },
{ "\"", XKB_KEY_quotedbl },
{ "#", XKB_KEY_numbersign },
{ "$", XKB_KEY_dollar },
{ "%", XKB_KEY_percent },
{ "&", XKB_KEY_ampersand },
{ "'", XKB_KEY_apostrophe },
{ "(", XKB_KEY_parenleft },
{ ")", XKB_KEY_parenright },
{ "*", XKB_KEY_asterisk },
{ "+", XKB_KEY_plus },
{ ",", XKB_KEY_comma },
{ "-", XKB_KEY_minus },
{ ".", XKB_KEY_period },
{ "/", XKB_KEY_slash },
{ ":", XKB_KEY_colon },
{ ";", XKB_KEY_semicolon },
{ "<", XKB_KEY_less },
{ "=", XKB_KEY_equal },
{ ">", XKB_KEY_greater },
{ "?", XKB_KEY_question },
{ "@", XKB_KEY_at },
{ "[", XKB_KEY_bracketleft },
{ "\\", XKB_KEY_backslash },
{ "]", XKB_KEY_bracketright },
{ "_", XKB_KEY_underscore },
{ "grave", XKB_KEY_grave },
{ "{", XKB_KEY_braceleft },
{ "bar", XKB_KEY_bar },
{ "}", XKB_KEY_braceright },
{ "~", XKB_KEY_asciitilde },
{ "F1", XKB_KEY_F1 },
{ "F2", XKB_KEY_F2 },
{ "F3", XKB_KEY_F3 },
{ "F4", XKB_KEY_F4 },
{ "F5", XKB_KEY_F5 },
{ "F6", XKB_KEY_F6 },
{ "F7", XKB_KEY_F7 },
{ "F8", XKB_KEY_F8 },
{ "F9", XKB_KEY_F9 },
{ "F10", XKB_KEY_F10 },
{ "F11", XKB_KEY_F11 },
{ "F12", XKB_KEY_F12 },
{ "PageUp", XKB_KEY_Page_Up },
{ "PageDown", XKB_KEY_Page_Down },
{ "Home", XKB_KEY_Home },
{ "End", XKB_KEY_End },
{ "Delete", XKB_KEY_Delete },
{ "PrintScr", XKB_KEY_Print },
{ "Esc", XKB_KEY_Escape },
{ "Pause", XKB_KEY_Pause },
{ "ScrollLock", XKB_KEY_Scroll_Lock },
{ "Backspace", XKB_KEY_BackSpace },
{ "Up", XKB_KEY_Up },
{ "Down", XKB_KEY_Down },
{ "Left", XKB_KEY_Left },
{ "Right", XKB_KEY_Right },
{ "Next", XKB_KEY_Next },
{ "Prior", XKB_KEY_Prior },
};
#endif
typedef struct {
char *click;
unsigned int button;
} ButtonType;
#if USEWAYLAND
typedef struct {
char *click;
unsigned int button;
} WlButtonType;
#endif
typedef struct {
char *tclick;
unsigned int click;
@ -518,6 +664,14 @@ static ButtonType btp[] = {
{ "Scroll Down", Button5 },
};
#if USEWAYLAND
static WlButtonType w_btp[] = {
{ "Left Click", WL_Left },
{ "Middle Click", WL_Middle },
{ "Right Click", WL_Right },
};
#endif
static ClickType ctp[] = {
{ "ClickWindow", ClickWindow },
{ "ClickPrompt", ClickPrompt },
@ -529,18 +683,6 @@ static ClickType ctp[] = {
{ "ClickNumber", ClickNumber },
{ "ClickCaps", ClickCaps },
{ "ClickMode", ClickMode },
// compatibility
{ "clickwindow", ClickWindow },
{ "clickprompt", ClickPrompt },
{ "clickinput", ClickInput },
{ "clicklarrow", ClickLArrow },
{ "clickitem", ClickItem },
{ "clickselitem", ClickSelItem },
{ "clickrarrow", ClickRArrow },
{ "clicknumber", ClickNumber },
{ "clickcaps", ClickCaps },
{ "clickmode", ClickMode },
};
static void conf_init(void);

View file

@ -11,9 +11,6 @@ void drawhighlights(struct item *item, int x, int y, int w, int p, const char *i
if (!(strlen(itemtext) && strlen(text))) return;
drw_setscheme(drw, scheme[item == sel
? SchemeSelHighlight
: SchemeNormHighlight]);
for (i = 0, highlight = itemtext; *highlight && text[i];) {
if (((fuzzy && !fstrncmp(&(*highlight), &text[i], 1)) || (!fuzzy && *highlight == text[i]))) {
c = *highlight;
@ -29,7 +26,11 @@ void drawhighlights(struct item *item, int x, int y, int w, int p, const char *i
x + indent + (p),
y,
MIN(w - indent - lrpad, TEXTW(highlight) - lrpad),
bh, 0, highlight, 0, pango_highlight ? True : False);
bh, 0, highlight, 0, pango_highlight ? True : False,
item == sel ? col_hlselfg : col_hlnormfg,
item == sel ? col_hlselbg : col_hlnormbg,
item == sel ? alpha_hlselfg : alpha_hlnormfg,
item == sel ? alpha_hlselbg : alpha_hlnormbg);
highlight[1] = c;
i++;
}
@ -39,7 +40,6 @@ void drawhighlights(struct item *item, int x, int y, int w, int p, const char *i
int drawitemtext(struct item *item, int x, int y, int w) {
char buffer[MAXITEMLENGTH]; // buffer containing item text
Clr scm[2]; // color scheme
int leftpadding = lrpad / 2; // padding
int wr, rd; // character
int fg = 7; // foreground
@ -48,31 +48,54 @@ int drawitemtext(struct item *item, int x, int y, int w) {
int ignore = 0; // ignore colors
int selitem = 0;
int priitem = 0;
char *bgcol;
char *fgcol;
int bga;
int fga;
// memcpy the correct scheme
if (item == sel) {
memcpy(scm, scheme[SchemeItemSel], sizeof(scm));
selitem = 1;
bgcol = col_itemselbg;
fgcol = col_itemselfg;
bga = alpha_itemselbg;
fga = alpha_itemselfg;
if (item->hp) {
memcpy(scm, scheme[SchemeItemSelPri], sizeof(scm));
priitem = 1;
bgcol = col_itemselpribg;
fgcol = col_itemselprifg;
fga = alpha_itemselprifg;
bga = alpha_itemselpribg;
}
} else {
if (itemn) {
memcpy(scm, scheme[SchemeItemNorm2], sizeof(scm));
bgcol = col_itemnormbg2;
fgcol = col_itemnormfg2;
fga = alpha_itemnormfg2;
bga = alpha_itemnormbg2;
} else {
memcpy(scm, scheme[SchemeItemNorm1], sizeof(scm));
bgcol = col_itemnormbg;
fgcol = col_itemnormfg;
fga = alpha_itemnormfg;
bga = alpha_itemnormbg;
}
if (item->hp) {
memcpy(scm, scheme[SchemeItemNormPri], sizeof(scm));
priitem = 1;
bgcol = col_itemnormpribg;
fgcol = col_itemnormprifg;
fga = alpha_itemnormprifg;
bga = alpha_itemnormpribg;
}
}
if (is_selected(item->index)) {
memcpy(scm, scheme[SchemeItemMarked], sizeof(scm));
bgcol = col_itemmarkedbg;
fgcol = col_itemmarkedfg;
fga = alpha_itemmarkedfg;
bga = alpha_itemmarkedbg;
}
// apply extra padding
@ -85,9 +108,12 @@ int drawitemtext(struct item *item, int x, int y, int w) {
}
// don't color
if (!coloritems) memcpy(scm, scheme[SchemeItemNorm1], sizeof(scm));
drw_setscheme(drw, scm); // set scheme
if (!coloritems) {
bgcol = itemn ? col_itemnormbg2 : col_itemnormbg;
fgcol = itemn ? col_itemnormfg2 : col_itemnormfg;
bga = itemn ? alpha_itemnormbg2 : alpha_itemnormbg;
fga = itemn ? alpha_itemnormfg2 : alpha_itemnormfg;
}
// parse item text
for (wr = 0, rd = 0; item->text[rd]; rd++) {
@ -101,7 +127,7 @@ int drawitemtext(struct item *item, int x, int y, int w) {
}
apply_fribidi(buffer);
drw_text(drw, x, y, MIN(w, TEXTW(buffer) - lrpad) + leftpadding, bh, leftpadding, isrtl ? fribidi_text : buffer, 0, pango_item ? True : False);
drw_text(drw, x, y, MIN(w, TEXTW(buffer) - lrpad) + leftpadding, bh, leftpadding, isrtl ? fribidi_text : buffer, 0, pango_item ? True : False, fgcol, bgcol, fga, bga);
drawhighlights(item, x, y, MIN(w, TEXTW(buffer) - lrpad) + leftpadding, leftpadding, isrtl ? fribidi_text : buffer);
// position and width
@ -113,7 +139,7 @@ int drawitemtext(struct item *item, int x, int y, int w) {
char *character = item->text + rd + 1; // current character
// parse hex colors in scm, m is always the last character
// parse hex colors, m is always the last character
while (*character != 'm') {
unsigned nextchar = strtoul(character + 1, &character, 10);
if (ignore)
@ -123,62 +149,91 @@ int drawitemtext(struct item *item, int x, int y, int w) {
bgfg <<= 1;
continue;
}
if (bgfg == 4)
scm[0] = textclrs[fg = nextchar];
else if (bgfg == 6)
scm[1] = textclrs[bg = nextchar];
ignore = 1;
if (bgfg == 4) {
fgcol = txtcols[fg = nextchar];
} else if (bgfg == 6) {
bgcol = txtcols[bg = nextchar];
}
ignore = 1;
continue;
}
if (nextchar == 1) {
fg |= 8;
scm[0] = textclrs[fg];
fgcol = txtcols[fg];
} else if (nextchar == 22) {
fg &= ~8;
scm[0] = textclrs[fg];
fgcol = txtcols[fg];
} else if (nextchar == 38) {
bgfg = 2;
} else if (nextchar >= 30 && nextchar <= 37) {
fg = nextchar % 10 | (fg & 8);
scm[0] = textclrs[fg];
fgcol = txtcols[fg];
} else if (nextchar >= 40 && nextchar <= 47) {
bg = nextchar % 10;
scm[1] = textclrs[bg];
bgcol = txtcols[bg];
} else if (nextchar == 48) {
bgfg = 3;
} else if (nextchar == 0) {
// memcpy the correct scheme
if (item == sel) {
memcpy(scm, scheme[SchemeItemSel], sizeof(scm));
selitem = 1;
bgcol = col_itemselbg;
fgcol = col_itemselfg;
bga = alpha_itemselbg;
fga = alpha_itemselfg;
if (item->hp)
memcpy(scm, scheme[SchemeItemSelPri], sizeof(scm));
if (item->hp) {
priitem = 1;
bgcol = col_itemselpribg;
fgcol = col_itemselprifg;
fga = alpha_itemselprifg;
bga = alpha_itemselpribg;
}
} else {
if (itemn) {
memcpy(scm, scheme[SchemeItemNorm2], sizeof(scm));
bgcol = col_itemnormbg2;
fgcol = col_itemnormfg2;
fga = alpha_itemnormfg2;
bga = alpha_itemnormbg2;
} else {
memcpy(scm, scheme[SchemeItemNorm1], sizeof(scm));
bgcol = col_itemnormbg;
fgcol = col_itemnormfg;
fga = alpha_itemnormfg;
bga = alpha_itemnormbg;
}
if (item->hp)
memcpy(scm, scheme[SchemeItemNormPri], sizeof(scm));
if (item->hp) {
priitem = 1;
bgcol = col_itemnormpribg;
fgcol = col_itemnormprifg;
fga = alpha_itemnormprifg;
bga = alpha_itemnormpribg;
}
}
if (is_selected(item->index)) {
memcpy(scm, scheme[SchemeItemMarked], sizeof(scm));
bgcol = col_itemmarkedbg;
fgcol = col_itemmarkedfg;
fga = alpha_itemmarkedfg;
bga = alpha_itemmarkedbg;
}
// don't color
if (!coloritems) memcpy(scm, scheme[SchemeItemNorm1], sizeof(scm));
if (!coloritems) {
bgcol = itemn ? col_itemnormbg2 : col_itemnormbg;
fgcol = itemn ? col_itemnormfg2 : col_itemnormfg;
bga = itemn ? alpha_itemnormbg2 : alpha_itemnormbg;
fga = itemn ? alpha_itemnormfg2 : alpha_itemnormfg;
}
}
}
rd += alen + 2;
wr = 0;
drw_setscheme(drw, scm); // set scheme
continue;
}
}
@ -190,7 +245,7 @@ int drawitemtext(struct item *item, int x, int y, int w) {
// now draw any non-colored text
apply_fribidi(buffer);
int r = drw_text(drw, x, y, w, bh, leftpadding, isrtl ? fribidi_text : buffer, 0, pango_item ? True : False);
int r = drw_text(drw, x, y, w, bh, leftpadding, isrtl ? fribidi_text : buffer, 0, pango_item ? True : False, fgcol, bgcol, fga, bga);
if (!hidehighlight) drawhighlights(item, x, y, w, leftpadding, buffer);
// copy current buffer to item->clntext instead of item->text, this way SGR sequences aren't drawn
@ -231,7 +286,7 @@ int drawitem(int x, int y, int w) {
// draw image first
#if USEIMAGE
if (!hideimage && longestedge != 0) {
if (!hideimage && longestedge != 0 && !protocol) { // TODO: wayland image support
rx = ox;
rx += MAX((imagegaps * 2) + imagewidth + menumarginh, indentitems ? x : 0);
} else
@ -301,14 +356,10 @@ int drawitem(int x, int y, int w) {
int drawprompt(int x, int y, int w) {
if (prompt && *prompt && !hideprompt) {
drw_setscheme(drw, scheme[SchemePrompt]);
x = drw_text(drw, x, y, w, bh, lrpad / 2, prompt, 0, pango_prompt ? True : False);
x = drw_text(drw, x, y, w, bh, lrpad / 2, prompt, 0, pango_prompt ? True : False, col_promptfg, col_promptbg, alpha_promptfg, alpha_promptbg);
if (!hidepowerline && powerlineprompt) {
drw_settrans(drw, scheme[SchemePrompt], scheme[SchemeMenu]);
drw_arrow(drw, x, y, plw, bh, 1, promptpwlstyle);
drw_arrow(drw, x, y, plw, bh, 1, promptpwlstyle, col_menu, col_promptbg, alpha_menu, alpha_promptbg);
x += plw;
}
}
@ -321,9 +372,6 @@ int drawinput(int x, int y, int w) {
unsigned int curpos = 0;
int fh = drw->font->h;
// draw input
drw_setscheme(drw, scheme[SchemeInput]);
if (passwd) {
censort = ecalloc(1, sizeof(text));
@ -331,21 +379,20 @@ int drawinput(int x, int y, int w) {
memcpy(&censort[i], password, strlen(text));
apply_fribidi(censort);
drw_text(drw, x, y, w, bh, lrpad / 2, isrtl ? fribidi_text : censort, 0, pango_password ? True : False);
drw_text(drw, x, y, w, bh, lrpad / 2, isrtl ? fribidi_text : censort, 0, pango_password ? True : False, col_inputfg, col_inputbg, alpha_inputfg, alpha_inputbg);
curpos = TEXTW(censort) - TEXTW(&text[cursor]);
free(censort);
} else if (!passwd) {
apply_fribidi(text);
drw_text(drw, x, y, w, bh, lrpad / 2, isrtl ? fribidi_text : text, 0, pango_input ? True : False);
drw_text(drw, x, y, w, bh, lrpad / 2, isrtl ? fribidi_text : text, 0, pango_input ? True : False, col_inputfg, col_inputbg, alpha_inputfg, alpha_inputbg);
curpos = TEXTW(text) - TEXTW(&text[cursor]);
}
if ((curpos += lrpad / 2 - 1) < w && !hidecaret && cursorstate) {
drw_setscheme(drw, scheme[SchemeCaret]);
drw_rect(drw, x + curpos, 2 + (bh - fh) / 2 + y, 2, fh - 4, 1, 0);
drw_rect(drw, x + curpos, 2 + (bh - fh) / 2 + y, 2, fh - 4, 1, 0, col_caretfg, col_caretbg, alpha_caretfg, alpha_caretbg);
}
return x;
@ -355,8 +402,7 @@ int drawlarrow(int x, int y, int w) {
if (hidelarrow) return x;
if (curr->left) { // draw left arrow
drw_setscheme(drw, scheme[SchemeLArrow]);
drw_text(drw, x, y, w, bh, lrpad / 2, leftarrow, 0, pango_leftarrow ? True : False);
drw_text(drw, x, y, w, bh, lrpad / 2, leftarrow, 0, pango_leftarrow ? True : False, col_larrowfg, col_larrowbg, alpha_larrowfg, alpha_larrowbg);
x += w;
}
@ -367,8 +413,7 @@ int drawrarrow(int x, int y, int w) {
if (hiderarrow) return x;
if (next) { // draw right arrow
drw_setscheme(drw, scheme[SchemeRArrow]);
drw_text(drw, mw - w, y, w, bh, lrpad / 2, rightarrow, 0, pango_rightarrow ? True : False);
drw_text(drw, mw - w, y, w, bh, lrpad / 2, rightarrow, 0, pango_rightarrow ? True : False, col_rarrowfg, col_rarrowbg, alpha_rarrowfg, alpha_rarrowbg);
x += w;
}
@ -384,13 +429,11 @@ int drawnumber(int x, int y, int w) {
powerlinewidth = plw / 2;
}
drw_setscheme(drw, scheme[SchemeNumber]);
drw_text(drw, x, y, w, bh, lrpad / 2 + powerlinewidth, numbers, 0, pango_numbers ? True : False);
drw_text(drw, x, y, w, bh, lrpad / 2 + powerlinewidth, numbers, 0, pango_numbers ? True : False, col_numfg, col_numbg, alpha_numfg, alpha_numbg);
// draw powerline for match count
if (!hidepowerline && powerlinecount) {
drw_settrans(drw, scheme[SchemeNumber], scheme[SchemeMenu]);
drw_arrow(drw, x, y, plw, bh, 0, matchcountpwlstyle);
drw_arrow(drw, x, y, plw, bh, 0, matchcountpwlstyle, col_menu, col_numbg, alpha_menu, alpha_numbg);
x += plw;
}
@ -406,13 +449,13 @@ int drawmode(int x, int y, int w) {
powerlinewidth = plw / 2;
}
drw_setscheme(drw, scheme[SchemeMode]);
drw_text(drw, x, y, w, bh, lrpad / 2 + powerlinewidth, modetext, 0, pango_mode ? True : False);
drw_text(drw, x, y, w, bh, lrpad / 2 + powerlinewidth, modetext, 0, pango_mode ? True : False, col_modefg, col_modebg, alpha_modefg, alpha_modebg);
// draw powerline for match count
if (!hidepowerline && powerlinemode) {
drw_settrans(drw, scheme[SchemeMode], hidematchcount ? scheme[SchemeMenu] : scheme[SchemeNumber]);
drw_arrow(drw, x, y, plw, bh, 0, modepwlstyle);
drw_arrow(drw, x, y, plw, bh, 0, modepwlstyle,
hidematchcount ? col_menu : col_numbg, col_modebg,
hidematchcount ? alpha_menu : alpha_numbg, alpha_modebg);
x += plw;
}
@ -431,13 +474,13 @@ int drawcaps(int x, int y, int w) {
powerlinewidth = plw / 2;
}
drw_setscheme(drw, scheme[SchemeCaps]);
drw_text(drw, x, y, w, bh, lrpad / 2 + powerlinewidth, capstext, 0, pango_caps ? True : False);
drw_text(drw, x, y, w, bh, lrpad / 2 + powerlinewidth, capstext, 0, pango_caps ? True : False, col_capsfg, col_capsbg, alpha_capsfg, alpha_capsbg);
// draw powerline for caps lock indicator
if (!hidepowerline && powerlinecaps) {
drw_settrans(drw, scheme[SchemeCaps], hidemode ? hidematchcount ? scheme[SchemeMenu] : scheme[SchemeNumber] : scheme[SchemeMode]);
drw_arrow(drw, x, y, plw, bh, 0, capspwlstyle);
drw_arrow(drw, x, y, plw, bh, 0, capspwlstyle,
hidemode ? hidematchcount ? col_menu : col_numbg : col_modebg, col_capsbg,
hidemode ? hidematchcount ? alpha_menu : alpha_numbg : alpha_modebg, alpha_capsbg);
x += plw;
}
@ -447,12 +490,29 @@ int drawcaps(int x, int y, int w) {
}
void drawmenu(void) {
#if USEWAYLAND
if (protocol) {
readfile();
drawmenu_layer();
wl_surface_set_buffer_scale(state.surface, 1);
wl_surface_attach(state.surface, state.buffer, 0, 0);
wl_surface_damage(state.surface, 0, 0, state.width, state.height);
wl_surface_commit(state.surface);
} else {
drawmenu_layer();
}
#else
drawmenu_layer();
#endif
}
void drawmenu_layer(void) {
int x = 0, y = 0, w = 0;
plw = hidepowerline ? 0 : drw->font->h / 2 + 1; // powerline size
// draw menu first using menu scheme
drw_setscheme(drw, scheme[SchemeMenu]);
drw_rect(drw, 0, 0, mw, mh, 1, 1);
drw_rect(drw, 0, 0, mw, mh, 1, 1, col_menu, col_menu, alpha_menu, alpha_menu);
int numberWidth = 0;
int modeWidth = 0;
@ -486,15 +546,30 @@ void drawmenu(void) {
y -= bh;
mh = (lines + 1) * bh - bh + 2 * menumarginv;
if (!win) return;
if (!protocol) {
if (!win) {
return;
}
XResizeWindow(dpy, win, mw - 2 * sp - 2 * borderwidth, mh);
drw_resize(drw, mw - 2 * sp - 2 * borderwidth, mh);
} else {
resizeclient();
}
}
#if USEIMAGE
else if (hideprompt && hideinput && hidemode && hidematchcount && hidecaps) {
y -= bh;
mh = (lines + 1) * bh - bh + 2 * menumarginv;
#if USEWAYLAND
if (protocol) {
state.width = mw;
state.height = mh;
set_layer_size(&state, state.width, state.height);
}
#endif
}
#endif

View file

@ -1,6 +1,7 @@
/* See LICENSE file for copyright and license details. */
// declare functions
static void drawmenu_layer(void);
static void drawmenu(void);
static int drawprompt(int x, int y, int w);
static int drawinput(int x, int y, int w);

View file

@ -420,7 +420,7 @@ void resizetoimageheight(int imageheight) {
} else { // top or bottom
x = 0;
y = menuposition ? 0 : wa.height - mh - ypos;
mw = wa.width;
mw = (menuwidth > 0 ? menuwidth : wa.width);
}
}

View file

@ -11,11 +11,22 @@
#include "drw.h"
#include "../sl/main.h"
Clr transcheme[3]; // transition colorscheme
void cairo_set_source_hex(cairo_t* cr, const char *col, int alpha) {
unsigned int hex;
Drw *drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap) {
sscanf(col, "#%x", &hex);
double r = ((hex >> 16) & 0xFF) / 255.0;
double g = ((hex >> 8) & 0xFF) / 255.0;
double b = (hex & 0xFF) / 255.0;
cairo_set_source_rgba(cr, r, g, b, alpha / 255.0);
}
Drw *drw_create_x11(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap, int protocol) {
Drw *drw = ecalloc(1, sizeof(Drw));
drw->protocol = protocol;
drw->dpy = dpy;
drw->screen = screen;
drw->root = root;
@ -31,6 +42,22 @@ Drw *drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned
return drw;
}
Drw *drw_create_wl(int protocol) {
Drw *drw = ecalloc(1, sizeof(Drw));
drw->protocol = protocol;
return drw;
}
void drw_create_surface_wl(Drw *drw, void *data, int32_t w, int32_t h) {
drw->data = data;
drw->w = w;
drw->h = h;
drw->surface = cairo_image_surface_create_for_data(drw->data, CAIRO_FORMAT_ARGB32, drw->w, drw->h, drw->w * 4);
drw->d = cairo_create(drw->surface);
}
void drw_resize(Drw *drw, unsigned int w, unsigned int h) {
if (!drw)
return;
@ -45,13 +72,17 @@ void drw_resize(Drw *drw, unsigned int w, unsigned int h) {
}
void drw_free(Drw *drw) {
if (!drw->protocol) {
XFreePixmap(drw->dpy, drw->drawable);
XFreeGC(drw->dpy, drw->gc);
}
drw_font_free(drw->font);
free(drw);
}
static Fnt *xfont_create(Drw *drw, const char *fontname) {
static Fnt *font_create(Drw *drw, const char *fontname) {
Fnt *font;
PangoFontMap *fontmap;
PangoContext *context;
@ -80,7 +111,7 @@ static Fnt *xfont_create(Drw *drw, const char *fontname) {
return font;
}
void xfont_free(Fnt *font) {
void font_free(Fnt *font) {
if (!font)
return;
if (font->layout)
@ -94,126 +125,116 @@ Fnt* drw_font_create(Drw* drw, char *font[], size_t fontcount) {
Fnt *fnt = NULL;
fnt = xfont_create(drw, *font);
fnt = font_create(drw, *font);
return (drw->font = fnt);
}
void drw_font_free(Fnt *font) {
if (font) {
xfont_free(font);
font_free(font);
}
}
void drw_clr_create(Drw *drw, Clr *dest, char *clrname, unsigned int alpha) {
XColor color;
if (!drw || !dest || !clrname)
return;
if (!XAllocNamedColor(drw->dpy, drw->cmap, clrname, &color, dest))
die("spmenu: cannot allocate color '%s'", clrname);
dest->red = color.red;
dest->green = color.green;
dest->blue = color.blue;
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, char *clrnames[], unsigned int alphas[], size_t clrcount) {
size_t i;
Clr *ret;
/* need at least two colors for a scheme */
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XColor))))
return NULL;
for (i = 0; i < clrcount; i++)
drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
return ret;
}
void drw_setscheme(Drw *drw, Clr *scm) {
if (drw)
drw->scheme = scm;
}
void drw_settrans(Drw *drw, Clr *psc, Clr *nsc) {
if (drw) {
transcheme[0] = psc[ColBg]; transcheme[1] = nsc[ColBg]; transcheme[2] = psc[ColPwl];
drw->scheme = transcheme;
}
}
void drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash) {
if (!drw || !drw->scheme)
void drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash, char *prevcol, char *nextcol, int prevalpha, int nextalpha) {
if (!drw)
return;
x = direction ? x : x + w;
w = direction ? w : - w;
unsigned int hh = slash ? (direction ? 0 : h) : h/2;
XPoint points[] = {
{x , y },
{x + w, y + hh },
{x , y + h },
};
double hh = slash ? (direction ? 0 : h) : h / 2;
XPoint bg[] = {
{x , y },
{x + w, y },
{x + w, y + h},
{x , y + h},
};
cairo_surface_t *sf = NULL;
XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
XFillPolygon(drw->dpy, drw->drawable, drw->gc, bg, 4, Convex, CoordModeOrigin);
XSetForeground(drw->dpy, drw->gc, drw->scheme[ColFg].pixel);
XFillPolygon(drw->dpy, drw->drawable, drw->gc, points, 3, Nonconvex, CoordModeOrigin);
if (drw->protocol) {
sf = cairo_image_surface_create_for_data(drw->data, CAIRO_FORMAT_ARGB32, drw->w, drw->h, drw->w * 4);
} else {
sf = cairo_xlib_surface_create(drw->dpy, drw->drawable, drw->visual, drw->w, drw->h);
}
cairo_t *cr = cairo_create(sf);
cairo_set_source_hex(cr, prevcol, prevalpha);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_rectangle(cr, x, y, w, h);
cairo_fill(cr);
cairo_move_to(cr, x, y);
cairo_line_to(cr, x + w, y + hh);
cairo_line_to(cr, x, y + h);
cairo_close_path(cr);
cairo_set_source_hex(cr, nextcol, nextalpha);
cairo_fill(cr);
cairo_destroy(cr);
cairo_surface_destroy(sf);
}
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) {
if (!drw || !drw->scheme)
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert, char *fgcol, char *bgcol, int fgalpha, int bgalpha) {
if (!drw) {
return;
XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
if (filled)
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
else
XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
}
int xerrordummy(Display *dpy, XErrorEvent *ee) {
return 0;
cairo_surface_t *sf;
if (drw->protocol) {
sf = cairo_image_surface_create_for_data(drw->data, CAIRO_FORMAT_ARGB32, drw->w, drw->h, drw->w * 4);
} else {
sf = cairo_xlib_surface_create(drw->dpy, drw->drawable, drw->visual, drw->w, drw->h);
}
cairo_t *cr = cairo_create(sf);
if (!cr) {
die("failed to create cairo context");
}
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) {
cairo_set_source_hex(cr, invert ? bgcol : fgcol, invert ? bgalpha : fgalpha);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
if (filled) {
cairo_rectangle(cr, x, y, w, h);
cairo_fill(cr);
} else {
cairo_rectangle(cr, x, y, w - 1, h - 1);
cairo_stroke(cr);
}
cairo_destroy(cr);
cairo_surface_destroy(sf);
}
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, char *fgcol, char *bgcol, int fgalpha, int bgalpha) {
char buf[1024];
int ty;
unsigned int ew = 0;
size_t i, len;
int render = x || y || w || h;
char *t;
XSetErrorHandler(xerrordummy);
if (!drw || (render && !drw->scheme) || !text || !drw->font)
if (!drw || !text || !drw->font) {
return 0;
}
if (!render) {
w = ~w;
} else {
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
drw->surface = cairo_xlib_surface_create(drw->dpy, drw->drawable, drw->visual, drw->w, drw->h);
drw->d = cairo_create(drw->surface);
x += lpad;
w -= lpad;
if (drw->protocol) {
drw->surface = cairo_image_surface_create_for_data(drw->data, CAIRO_FORMAT_ARGB32, drw->w, drw->h, drw->w * 4);
} else {
drw->surface = cairo_xlib_surface_create(drw->dpy, drw->drawable, drw->visual, drw->w, drw->h);
}
drw->d = cairo_create(drw->surface);
// draw bg
cairo_set_source_hex(drw->d, invert ? fgcol : bgcol, invert ? fgalpha : bgalpha);
cairo_set_operator(drw->d, CAIRO_OPERATOR_SOURCE);
cairo_rectangle(drw->d, x - lpad, y, w + lpad, h);
cairo_fill(drw->d);
}
t = strdup(text);
@ -237,8 +258,6 @@ int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned in
markup = 0;
if (render) {
ty = y + (h - drw->font->h) / 2;
if (markup) {
pango_layout_set_markup(drw->font->layout, buf, len);
} else {
@ -247,12 +266,16 @@ int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned in
pango_layout_set_single_paragraph_mode(drw->font->layout, True);
cairo_set_source_rgb(drw->d, convert_color(drw->scheme->red), convert_color(drw->scheme->green), convert_color(drw->scheme->blue));
cairo_move_to(drw->d, x, ty);
// draw fg
cairo_set_source_hex(drw->d, fgcol, fgalpha);
cairo_move_to(drw->d, x, y + (h - drw->font->h) / 2);
// update and show layout
pango_cairo_update_layout(drw->d, drw->font->layout);
pango_cairo_show_layout(drw->d, drw->font->layout);
cairo_set_operator(drw->d, CAIRO_OPERATOR_SOURCE);
if (markup) // clear markup attributes
pango_layout_set_attributes(drw->font->layout, NULL);
}
@ -269,14 +292,16 @@ void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
if (!drw)
return;
if (!drw->protocol) {
XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
XSync(drw->dpy, False);
}
}
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);
return drw_text(drw, 0, 0, 0, 0, 0, text, 0, markup, "#000000", "#000000", 255, 255);
}
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup) {
@ -329,6 +354,6 @@ void drw_cur_free(Drw *drw, Cur *cursor) {
unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n, Bool markup) {
unsigned int tmp = 0;
if (drw && drw->font && text && n)
tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n, markup);
tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n, markup, "#000000", "#000000", 255, 255);
return MIN(n, tmp);
}

View file

@ -6,40 +6,41 @@
#include <pango/pango.h>
#include <pango/pangocairo.h>
#define convert_color(x) (double)((x) / 65535.0)
typedef struct {
Cursor cursor;
} Cur;
typedef XColor Clr;
typedef struct Fnt {
Display *dpy;
unsigned int h;
PangoLayout *layout;
} Fnt;
enum { ColFg, ColBg, ColPwl }; /* Clr scheme index */
typedef struct {
unsigned int w, h;
int protocol;
Display *dpy;
int screen;
Window root;
Visual *visual;
unsigned int depth;
void *data;
Colormap cmap;
Drawable drawable;
GC gc;
Clr *scheme;
Fnt *font;
cairo_surface_t *surface;
cairo_t *d;
} Drw;
/* Cairo color convertion */
void cairo_set_source_hex(cairo_t* cr, const char *col, int alpha);
/* Drawable abstraction */
Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap);
Drw *drw_create_x11(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap, int protocol);
Drw *drw_create_wl(int protocol);
void drw_create_surface_wl(Drw *drw, void *data, int32_t w, int32_t h);
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
void drw_free(Drw *drw);
@ -50,24 +51,16 @@ unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int
unsigned int drw_font_getwidth(Drw *drw, const char *text, Bool markup);
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup);
/* Colorscheme abstraction */
void drw_clr_create(Drw *drw, Clr *dest, char *clrname, unsigned int alpha);
Clr *drw_scm_create(Drw *drw, char *clrnames[], unsigned int alphas[], size_t clrcount);
/* Cursor abstraction */
Cur *drw_cur_create(Drw *drw, int shape);
void drw_cur_free(Drw *drw, Cur *cursor);
/* Drawing context manipulation */
void drw_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, Bool markup);
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert, char *fgcol, char *bgcol, int fgalpha, int bgalpha);
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, char *fgcol, char *bgcol, int fgalpha, int bgalpha);
/* Map functions */
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
/* Powerline functions */
void drw_settrans(Drw *drw, Clr *psc, Clr *nsc);
void drw_arrow(Drw* drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash);
void drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash, char *prevcol, char *nextcol, int prevalpha, int nextalpha);

View file

@ -33,11 +33,7 @@ void fuzzymatch(void) {
}
// 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++;
}
@ -79,16 +75,20 @@ void fuzzymatch(void) {
for (i = 0; i < preselected; i++) {
if (sel && sel->right && (sel = sel->right) == next) {
curr = next;
calcoffsets();
}
}
}
calcoffsets();
}
void match(void) {
get_width();
if (fuzzy) {
fuzzymatch();
return;
}
static char **tokv = NULL;
static int tokn = 0;
@ -103,6 +103,7 @@ void match(void) {
for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " "))
if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))
die("spmenu: cannot realloc %u bytes:", tokn * sizeof *tokv);
len = tokc ? strlen(tokv[0]) : 0;
matches = lhpprefix = lprefix = lsubstr = matchend = hpprefixend = prefixend = substrend = NULL;

View file

@ -9,83 +9,44 @@ void init_appearance(void) {
char cbuf[8];
// set alpha
alphas[SchemeLArrow][ColFg] = alpha_larrowfg;
alphas[SchemeLArrow][ColBg] = alpha_larrowbg;
alphas[SchemeRArrow][ColFg] = alpha_rarrowfg;
alphas[SchemeRArrow][ColBg] = alpha_rarrowbg;
alphas[SchemeItemNorm1][ColFg] = alpha_itemnormfg;
alphas[SchemeItemNorm1][ColBg] = alpha_itemnormbg;
alphas[SchemeItemNorm2][ColFg] = alpha_itemnormfg2;
alphas[SchemeItemNorm2][ColBg] = alpha_itemnormbg2;
alphas[SchemeItemSel][ColFg] = alpha_itemselfg;
alphas[SchemeItemSel][ColBg] = alpha_itemselbg;
alphas[SchemeItemMarked][ColFg] = alpha_itemmarkedfg;
alphas[SchemeItemMarked][ColBg] = alpha_itemmarkedbg;
alphas[SchemeItemNormPri][ColFg] = alpha_itemnormprifg;
alphas[SchemeItemNormPri][ColBg] = alpha_itemnormpribg;
alphas[SchemeItemSelPri][ColFg] = alpha_itemselprifg;
alphas[SchemeItemSelPri][ColBg] = alpha_itemselpribg;
alphas[SchemeMenu][ColBg] = alpha_menu;
alphas[SchemeInput][ColFg] = alpha_inputfg;
alphas[SchemeInput][ColBg] = alpha_inputbg;
alphas[SchemePrompt][ColFg] = alpha_promptfg;
alphas[SchemePrompt][ColBg] = alpha_promptbg;
alphas[SchemeNormHighlight][ColFg] = alpha_hlnormfg;
alphas[SchemeNormHighlight][ColBg] = alpha_hlnormbg;
alphas[SchemeSelHighlight][ColFg] = alpha_hlselfg;
alphas[SchemeSelHighlight][ColBg] = alpha_hlselbg;
alphas[SchemeCaret][ColFg] = alpha_caretfg;
alphas[SchemeCaret][ColBg] = alpha_caretbg;
alphas[SchemeNumber][ColFg] = alpha_numfg;
alphas[SchemeNumber][ColBg] = alpha_numbg;
alphas[SchemeMode][ColFg] = alpha_modefg;
alphas[SchemeMode][ColBg] = alpha_modebg;
alphas[SchemeCaps][ColFg] = alpha_capsfg;
alphas[SchemeCaps][ColBg] = alpha_capsbg;
alphas[SchemeBorder][ColBg] = alpha_border;
// create color schemes from array
scheme = ecalloc(LENGTH(colors) + 1, sizeof(Clr *));
scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], alphas[i], 2);
for (i = 0; i < LENGTH(colors) && i < LENGTH(alphas); i++)
scheme[i] = drw_scm_create(drw, colors[i], alphas[i], 2);
for (i = 0; i < LENGTH(textcolors) && i < LENGTH(textclrs); i++)
drw_clr_create(drw, &textclrs[i], textcolors[i], 0);
if (i == 0)
drw_clr_create(drw, &textclrs[i++], "#000000", 0);
for (i = 0; i < LENGTH(textcolors) && i < LENGTH(txtcols); i++) {
txtcols[i] = textcolors[i];
}
if (i == 0) {
txtcols[i] = "#000000";
}
for (; i < 7; i++) {
snprintf(cbuf, sizeof(cbuf), "#%02x%02x%02x",
!!(i & 1) * 0x7f,
!!(i & 2) * 0x7f,
!!(i & 4) * 0x7f);
drw_clr_create(drw, &textclrs[i], cbuf, 0);
txtcols[i] = cbuf;
}
if (i == 7) {
txtcols[i] = "#000000";
}
if (i == 8) {
txtcols[i] = "#333333";
}
if (i == 7)
drw_clr_create(drw, &textclrs[i++], "#000000", 0);
if (i == 8)
drw_clr_create(drw, &textclrs[i++], "#333333", 0);
for (; i < 16; i++) {
snprintf(cbuf, sizeof(cbuf), "#%02x%02x%02x",
!!(i & 1) * 0xff,
!!(i & 2) * 0xff,
!!(i & 4) * 0xff);
drw_clr_create(drw, &textclrs[i], cbuf, 0);
txtcols[i] = cbuf;
}
for (; i < 6 * 6 * 6 + 16; i++) {
snprintf(cbuf, sizeof(cbuf), "#%02x%02x%02x",
sixd_to_8bit(((i - 16) / 36) % 6),
sixd_to_8bit(((i - 16) / 6) % 6),
sixd_to_8bit(((i - 16)) % 6));
drw_clr_create(drw, &textclrs[i], cbuf, 0);
txtcols[i] = cbuf;
}
for (; i < 256; i++) {
snprintf(cbuf, sizeof(cbuf), "#%02x%02x%02x",
0x08 + (i - 6 * 6 * 6 - 16) * 0x0a,
0x08 + (i - 6 * 6 * 6 - 16) * 0x0a,
0x08 + (i - 6 * 6 * 6 - 16) * 0x0a);
drw_clr_create(drw, &textclrs[i], cbuf, 0);
txtcols[i] = cbuf;
}
}

View file

@ -1,25 +1,3 @@
/* See LICENSE file for copyright and license details. */
static void init_appearance(void);
// Color schemes
enum {
SchemeLArrow,
SchemeRArrow,
SchemeItemNorm1,
SchemeItemNorm2,
SchemeItemSel,
SchemeItemNormPri,
SchemeItemSelPri,
SchemeItemMarked,
SchemeMenu,
SchemeInput,
SchemePrompt,
SchemeNormHighlight,
SchemeSelHighlight,
SchemeCaret,
SchemeNumber,
SchemeMode,
SchemeBorder,
SchemeCaps,
};

View file

@ -2,7 +2,7 @@
void readstdin(void) {
char buf[sizeof text], *p;
size_t i, imax = 0, itemsiz = 0;
size_t i, itemsiz = 0;
unsigned int tmpmax = 0;
if (passwd) {
@ -32,7 +32,6 @@ void readstdin(void) {
drw_font_getexts(drw->font, buf, strlen(buf), &tmpmax, NULL, True);
if (tmpmax > inputw) {
inputw = tmpmax;
imax = i;
}
items[i].index = i;
@ -60,7 +59,6 @@ void readstdin(void) {
#endif
}
inputw = items ? TEXTWM(items[imax].text) : 0;
lines = MIN(lines, i);
}
@ -128,7 +126,6 @@ void readfile(void) {
#endif
}
inputw = items ? TEXTWM(items[i].text) : 0;
lines = columns == 1 ? i : MIN(i, lines); // i = number of items
#if USEIMAGE
@ -141,8 +138,11 @@ void readfile(void) {
listcount = i;
listchanged = 1;
// prevents state->buffer from being NULL
if (!protocol) {
resizeclient();
}
}
} else {
free(items);
items = list_items;

View file

@ -7,7 +7,7 @@ void theme_load(void) {
const char *dest;
// don't load configuration
if (!loadconfig) return;
if (!loadtheme) return;
// get path for configuration file
if (!argtheme) {
@ -212,125 +212,125 @@ void theme_load(void) {
// items
if (config_setting_lookup_string(conf, "itemnormfg", &dest))
strcpy(colors[SchemeItemNorm1][ColFg], strdup(dest));
strcpy(col_itemnormfg, strdup(dest));
if (config_setting_lookup_string(conf, "itemnormbg", &dest))
strcpy(colors[SchemeItemNorm1][ColBg], strdup(dest));
strcpy(col_itemnormbg, strdup(dest));
if (config_setting_lookup_string(conf, "itemnormfg2", &dest))
strcpy(colors[SchemeItemNorm2][ColFg], strdup(dest));
strcpy(col_itemnormfg2, strdup(dest));
else if (config_setting_lookup_string(conf, "itemnormfg", &dest))
strcpy(colors[SchemeItemNorm2][ColBg], strdup(dest));
strcpy(col_itemnormfg2, strdup(dest));
if (config_setting_lookup_string(conf, "itemnormbg2", &dest))
strcpy(colors[SchemeItemNorm2][ColBg], strdup(dest));
strcpy(col_itemnormbg2, strdup(dest));
else if (config_setting_lookup_string(conf, "itemnormbg", &dest))
strcpy(colors[SchemeItemNorm2][ColBg], strdup(dest));
strcpy(col_itemnormbg2, strdup(dest));
if (config_setting_lookup_string(conf, "itemselfg", &dest))
strcpy(colors[SchemeItemSel][ColFg], strdup(dest));
strcpy(col_itemselfg, strdup(dest));
if (config_setting_lookup_string(conf, "itemselbg", &dest))
strcpy(colors[SchemeItemSel][ColBg], strdup(dest));
strcpy(col_itemselbg, strdup(dest));
if (config_setting_lookup_string(conf, "itemmarkedfg", &dest))
strcpy(colors[SchemeItemMarked][ColFg], strdup(dest));
strcpy(col_itemmarkedfg, strdup(dest));
else if (config_setting_lookup_string(conf, "itemselfg", &dest))
strcpy(colors[SchemeItemMarked][ColFg], strdup(dest));
strcpy(col_itemmarkedfg, strdup(dest));
if (config_setting_lookup_string(conf, "itemmarkedbg", &dest))
strcpy(colors[SchemeItemMarked][ColBg], strdup(dest));
strcpy(col_itemmarkedbg, strdup(dest));
else if (config_setting_lookup_string(conf, "itemselbg", &dest))
strcpy(colors[SchemeItemMarked][ColBg], strdup(dest));
strcpy(col_itemmarkedbg, strdup(dest));
// items with priority
if (config_setting_lookup_string(conf, "itemnormprifg", &dest))
strcpy(colors[SchemeItemNormPri][ColFg], strdup(dest));
strcpy(col_itemnormprifg, strdup(dest));
if (config_setting_lookup_string(conf, "itemnormpribg", &dest))
strcpy(colors[SchemeItemNormPri][ColBg], strdup(dest));
strcpy(col_itemnormpribg, strdup(dest));
if (config_setting_lookup_string(conf, "itemselprifg", &dest))
strcpy(colors[SchemeItemSelPri][ColFg], strdup(dest));
strcpy(col_itemselprifg, strdup(dest));
if (config_setting_lookup_string(conf, "itemselpribg", &dest))
strcpy(colors[SchemeItemSelPri][ColBg], strdup(dest));
strcpy(col_itemselpribg, strdup(dest));
// input
if (config_setting_lookup_string(conf, "inputfg", &dest))
strcpy(colors[SchemeInput][ColFg], strdup(dest));
strcpy(col_inputfg, strdup(dest));
if (config_setting_lookup_string(conf, "inputbg", &dest))
strcpy(colors[SchemeInput][ColBg], strdup(dest));
strcpy(col_inputbg, strdup(dest));
// menu
if (config_setting_lookup_string(conf, "menu", &dest))
strcpy(colors[SchemeMenu][ColBg], strdup(dest));
strcpy(col_menu, strdup(dest));
// prompt
if (config_setting_lookup_string(conf, "promptfg", &dest))
strcpy(colors[SchemePrompt][ColFg], strdup(dest));
strcpy(col_promptfg, strdup(dest));
if (config_setting_lookup_string(conf, "promptbg", &dest))
strcpy(colors[SchemePrompt][ColBg], strdup(dest));
strcpy(col_promptbg, strdup(dest));
// arrows
if (config_setting_lookup_string(conf, "larrowfg", &dest))
strcpy(colors[SchemeLArrow][ColFg], strdup(dest));
strcpy(col_larrowfg, strdup(dest));
if (config_setting_lookup_string(conf, "larrowbg", &dest))
strcpy(colors[SchemeLArrow][ColBg], strdup(dest));
strcpy(col_larrowbg, strdup(dest));
if (config_setting_lookup_string(conf, "rarrowfg", &dest))
strcpy(colors[SchemeRArrow][ColFg], strdup(dest));
strcpy(col_rarrowfg, strdup(dest));
if (config_setting_lookup_string(conf, "rarrowbg", &dest))
strcpy(colors[SchemeRArrow][ColBg], strdup(dest));
strcpy(col_rarrowbg, strdup(dest));
// highlight
if (config_setting_lookup_string(conf, "hlnormfg", &dest))
strcpy(colors[SchemeNormHighlight][ColFg], strdup(dest));
strcpy(col_hlnormfg, strdup(dest));
if (config_setting_lookup_string(conf, "hlnormbg", &dest))
strcpy(colors[SchemeNormHighlight][ColBg], strdup(dest));
strcpy(col_hlnormbg, strdup(dest));
if (config_setting_lookup_string(conf, "hlselfg", &dest))
strcpy(colors[SchemeSelHighlight][ColFg], strdup(dest));
strcpy(col_hlselfg, strdup(dest));
if (config_setting_lookup_string(conf, "hlselbg", &dest))
strcpy(colors[SchemeSelHighlight][ColBg], strdup(dest));
strcpy(col_hlselbg, strdup(dest));
// number
if (config_setting_lookup_string(conf, "numfg", &dest))
strcpy(colors[SchemeNumber][ColFg], strdup(dest));
strcpy(col_numfg, strdup(dest));
if (config_setting_lookup_string(conf, "numbg", &dest))
strcpy(colors[SchemeNumber][ColBg], strdup(dest));
strcpy(col_numbg, strdup(dest));
// mode
if (config_setting_lookup_string(conf, "modefg", &dest))
strcpy(colors[SchemeMode][ColFg], strdup(dest));
strcpy(col_modefg, strdup(dest));
if (config_setting_lookup_string(conf, "modebg", &dest))
strcpy(colors[SchemeMode][ColBg], strdup(dest));
strcpy(col_modebg, strdup(dest));
// caps
if (config_setting_lookup_string(conf, "capsfg", &dest))
strcpy(colors[SchemeCaps][ColFg], strdup(dest));
strcpy(col_capsfg, strdup(dest));
if (config_setting_lookup_string(conf, "capsbg", &dest))
strcpy(colors[SchemeCaps][ColBg], strdup(dest));
strcpy(col_capsbg, strdup(dest));
// border
if (config_setting_lookup_string(conf, "border", &dest))
strcpy(colors[SchemeBorder][ColBg], strdup(dest));
strcpy(col_border, strdup(dest));
// caret
if (config_setting_lookup_string(conf, "caretfg", &dest))
strcpy(colors[SchemeCaret][ColFg], strdup(dest));
strcpy(col_caretfg, strdup(dest));
if (config_setting_lookup_string(conf, "caretbg", &dest))
strcpy(colors[SchemeCaret][ColBg], strdup(dest));
strcpy(col_caretbg, strdup(dest));
// sgr colors
if (config_setting_lookup_string(conf, "sgr0", &dest))

6
libs/wl/inc.c Normal file
View file

@ -0,0 +1,6 @@
/* See LICENSE file for copyright and license details. */
#if USEWAYLAND
#include "wayland.c"
#include "init.c"
#endif

6
libs/wl/inc.h Normal file
View file

@ -0,0 +1,6 @@
/* See LICENSE file for copyright and license details. */
#if USEWAYLAND
#include "wayland.h"
#include "init.h"
#endif

64
libs/wl/init.c Normal file
View file

@ -0,0 +1,64 @@
/* See LICENSE file for copyright and license details. */
void prepare_window_size_wl(void) {
sp = menupaddingh;
vp = (menuposition == 1) ? menupaddingv : - menupaddingv;
bh = MAX(drw->font->h, drw->font->h + 2 + lineheight);
lines = MAX(lines, 0);
reallines = lines;
lrpad = drw->font->h + textpadding;
return;
}
void handle_wl(void) {
if (!setlocale(LC_CTYPE, "")) {
die("spmenu: no locale support");
}
prepare_window_size_wl();
promptw = (prompt && *prompt) ? pango_prompt ? TEXTWM(prompt) : TEXTW(prompt) - lrpad / 4 : 0;
allow_draw = 1;
init_keys(&state);
init_disp(&state);
if (no_display) {
protocol = 0;
handle();
return;
}
create_layer(&state, "spmenu");
mw = (menuwidth > 0 ? menuwidth : output_width);
mh = (lines + 1) * bh + 2 * menumarginv;
if (menuposition == 2) {
mw = MIN(MAX(max_textw() + promptw, minwidth), output_width);
}
state.width = mw;
state.height = mh;
set_layer_size(&state, state.width, state.height);
anchor_layer(&state, menuposition);
set_exclusive_zone(&state, -1);
set_keyboard(&state, 1);
add_layer_listener(&state);
set_visible_layer(&state);
roundtrip(&state);
match();
draw_sf(&state);
while (wl_display_dispatch(state.display) != -1) {
}
wl_display_disconnect(state.display);
}

3
libs/wl/init.h Normal file
View file

@ -0,0 +1,3 @@
/* See LICENSE file for copyright and license details. */
static void handle_wl(void);

43
libs/wl/shm.c Normal file
View file

@ -0,0 +1,43 @@
void randname(char *buf) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
long r = ts.tv_nsec;
for (int i = 0; i < 6; ++i) {
buf[i] = 'A'+(r&15)+(r&16)*2;
r >>= 5;
}
}
int anonymous_shm_open(void) {
char name[] = "/shm-XXXXXX";
int retries = 100;
do {
randname(name + strlen(name) - 6);
--retries;
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd >= 0) {
shm_unlink(name);
return fd;
}
} while (retries > 0 && errno == EEXIST);
return -1;
}
int create_shm_file(off_t size) {
int fd = anonymous_shm_open();
if (fd < 0) {
return fd;
}
if (ftruncate(fd, size) < 0) {
close(fd);
return -1;
}
return fd;
}

666
libs/wl/wayland.c Normal file
View file

@ -0,0 +1,666 @@
/* See LICENSE file for copyright and license details. */
#include "shm.c"
struct wl_buffer *create_buffer(struct state *state) {
int32_t width = state->width;
int32_t height = state->height;
uint32_t stride = width * 4;
size_t siz = stride * height;
int fd = create_shm_file(siz);
assert(fd != -1);
void *data = mmap(NULL, siz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
close(fd);
return NULL;
}
struct wl_shm_pool *pool = wl_shm_create_pool(state->shm, fd, siz);
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0,
width, height, stride, WL_SHM_FORMAT_ARGB8888);
wl_shm_pool_destroy(pool);
wl_buffer_add_listener(buffer, &buffer_listener, state);
state->data = data;
return buffer;
}
/* I fucking hate this code, but I'm not sure how else to do it.
*
* PLEASE submit a patch if you have an improvement.
*/
int is_correct_modifier(struct state *state, char *modifier) {
int altPress = xkb_state_mod_name_is_active(state->xkb_state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
int shiftPress = xkb_state_mod_name_is_active(state->xkb_state, XKB_MOD_NAME_SHIFT, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
int ctrlPress = xkb_state_mod_name_is_active(state->xkb_state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
int logoPress = xkb_state_mod_name_is_active(state->xkb_state, XKB_MOD_NAME_LOGO, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
if (!strcmp(modifier, WL_CtrlShift) && shiftPress && ctrlPress) {
return 0;
} else if (!strcmp(modifier, WL_CtrlShiftSuper) && shiftPress && ctrlPress && logoPress) {
return 0;
} else if (!strcmp(modifier, WL_CtrlSuper) && ctrlPress && logoPress) {
return 0;
} else if (!strcmp(modifier, WL_CtrlAlt) && altPress && ctrlPress) {
return 0;
} else if (!strcmp(modifier, WL_CtrlAltShift) && ctrlPress && altPress && shiftPress) {
return 0;
} else if (!strcmp(modifier, WL_CtrlAltShiftSuper) && ctrlPress && altPress && shiftPress && logoPress) {
return 0;
} else if (!strcmp(modifier, WL_CtrlAltSuper) && ctrlPress && altPress && logoPress) {
return 0;
} else if (!strcmp(modifier, WL_AltShift) && altPress && shiftPress) {
return 0;
} else if (!strcmp(modifier, WL_Shift) && shiftPress) {
return 0;
} else if (!strcmp(modifier, WL_Ctrl) && ctrlPress) {
return 0;
} else if (!strcmp(modifier, WL_Alt) && altPress) {
return 0;
} else if (!strcmp(modifier, WL_Super) && logoPress) {
return 0;
} else if (!strcmp(modifier, WL_None) && !altPress && !shiftPress && !ctrlPress && !logoPress) {
return 0;
}
return 1;
}
void keypress_wl(struct state *state, enum wl_keyboard_key_state key_state, xkb_keysym_t sym) {
int i = 0;
char buf[8];
if (key_state != WL_KEYBOARD_KEY_STATE_PRESSED) { // Only activate on press, not release
return;
}
if (xkb_keysym_to_lower(sym) == wlhkeys[0].keysym && !is_correct_modifier(state, wlhkeys[0].modifier) && wlhkeys[0].func) {
wlhkeys[0].func(&(wlhkeys[0].arg));
}
for (i = 0; i < LENGTH(wl_keys); i++) {
if (ignoreglobalkeys) break;
if (xkb_keysym_to_lower(sym) == wl_keys[i].keysym && !is_correct_modifier(state, wl_keys[i].modifier) && wl_keys[i].func) {
if ((wl_keys[i].mode && curMode) || wl_keys[i].mode == -1) {
wl_keys[i].func(&(wl_keys[i].arg));
return;
} else if (!wl_keys[i].mode && !curMode) {
wl_keys[i].func(&(wl_keys[i].arg));
} else {
continue;
}
}
}
for (i = 0; i < LENGTH(wl_ckeys); i++) {
if (ignoreconfkeys) break;
if (xkb_keysym_to_lower(sym) == wl_ckeys[i].keysym && !is_correct_modifier(state, wl_ckeys[i].modifier) && wl_ckeys[i].func) {
if ((wl_ckeys[i].mode && curMode) || wl_ckeys[i].mode == -1) {
wl_ckeys[i].func(&(wl_ckeys[i].arg));
return;
} else if (!wl_ckeys[i].mode && !curMode) {
wl_ckeys[i].func(&(wl_ckeys[i].arg));
} else {
continue;
}
}
}
if (xkb_keysym_to_lower(sym) == XKB_KEY_Escape) {
return;
}
if (!type || !curMode) {
return;
}
if (xkb_keysym_to_utf8(sym, buf, 8)) {
if (allowkeys) {
insert(buf, strnlen(buf, 8));
} else {
allowkeys = !allowkeys;
}
drawmenu();
}
}
void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {
struct state *state = data;
int ocapslockstate = capslockstate;
xkb_state_update_mask(state->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
if (xkb_state_mod_name_is_active(state->xkb_state, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_EFFECTIVE)) {
capslockstate = 1;
} else {
capslockstate = 0;
}
if (ocapslockstate != capslockstate) {
strncpy(capstext, capslockstate ? capslockontext : capslockofftext, 15);
drawmenu();
}
}
void keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay) {
struct state *state = data;
state->delay = delay;
if (rate > 0) {
state->period = 1000 / rate;
} else {
state->period = -1;
}
}
void keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t _key_state) {
struct state *state = data;
enum wl_keyboard_key_state key_state = _key_state;
strncpy(capstext, capslockstate ? capslockontext : capslockofftext, 15);
xkb_keysym_t sym = xkb_state_key_get_one_sym(state->xkb_state, key + 8);
keypress_wl(state, key_state, sym);
if (key_state == WL_KEYBOARD_KEY_STATE_PRESSED && state->period >= 0) {
state->repeat_key_state = key_state;
state->repeat_sym = sym;
struct itimerspec spec = { 0 };
spec.it_value.tv_sec = state->delay / 1000;
spec.it_value.tv_nsec = (state->delay % 1000) * 1000000l;
timerfd_settime(state->timer, 0, &spec, NULL);
} else if (key_state == WL_KEYBOARD_KEY_STATE_RELEASED) {
struct itimerspec spec = { 0 };
timerfd_settime(state->timer, 0, &spec, NULL);
}
}
void keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) {
struct state *state = data;
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
close(fd);
exit(1);
return;
}
char *map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
if (map_shm == MAP_FAILED) {
close(fd);
die("MAP_FAILED");
return;
}
state->xkb_keymap = xkb_keymap_new_from_string(state->xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
munmap(map_shm, size);
close(fd);
state->xkb_state = xkb_state_new(state->xkb_keymap);
}
void buttonpress_wl(uint32_t button, double ex, double ey) {
struct item *item;
int x = 0;
int y = 0;
int w;
int h = bh;
int xpad = 0;
int item_num = 0;
unsigned int i, click;
if (ex == 0 && ey == 0) {
return; // While it is possible to click at this position, usually it means we're outside the window area.
}
if (!hidepowerline) {
x = xpad = plw;
}
x += menumarginh;
int larrowWidth = 0;
int rarrowWidth = 0;
int numberWidth = 0;
int modeWidth = 0;
int capsWidth = 0;
if (!hidelarrow) larrowWidth = pango_leftarrow ? TEXTWM(leftarrow) : TEXTW(leftarrow);
if (!hiderarrow) rarrowWidth = pango_rightarrow ? TEXTWM(rightarrow) : TEXTW(rightarrow);
if (!hidematchcount) numberWidth = pango_numbers ? TEXTWM(numbers) : TEXTW(numbers);
if (!hidemode) modeWidth = pango_mode ? TEXTWM(modetext) : TEXTW(modetext);
if (!hidecaps) capsWidth = pango_caps ? TEXTWM(capstext) : TEXTW(capstext);
if (!strcmp(capstext, "")) capsWidth = 0; // No caps lock width for no chars
click = ClickWindow; // Used as a default, will be overriden.
// check click position and override the value of click
if (ex < x + promptw + powerlineprompt ? plw : 0) { // prompt
click = ClickPrompt;
} else if ((ex > mw - capsWidth - 2 * sp - 2 * borderwidth - menumarginh) && !hidecaps && capsWidth) { // caps lock indicator
click = ClickCaps;
} else if (ex > mw - modeWidth - capsWidth - 2 * sp - 2 * borderwidth - menumarginh) { // mode indicator
click = ClickMode;
} else if (ex > mw - modeWidth - numberWidth - capsWidth - 2 * sp - 2 * borderwidth - menumarginh) { // match count
click = ClickNumber;
} else { // input
w = (lines > 0 || !matches) ? mw - x : inputw;
if ((lines <= 0 && ex >= 0 && ex <= x + w + promptw +
((!prev || !curr->left) ? larrowWidth : 0)) ||
(lines > 0 && ey >= y && ey <= y + h)) {
click = ClickInput;
}
}
// item click
if (lines > 0) {
// vertical list
w = mw - x;
for (item = curr; item != next; item = item->right) {
if (item_num++ == lines) {
item_num = 1;
x += w / columns;
y = 0;
}
y += h;
// ClickSelItem, called function doesn't matter
if (ey >= y && ey <= (y + h) && ex >= x && ex <= (x + w / columns)) {
for (i = 0; i < LENGTH(wl_buttons); i++) {
if (ignoreglobalmouse) break;
if (wl_buttons[i].click == ClickSelItem && wl_buttons[i].button == button) {
puts(item->text);
exit(0);
} else if (wl_buttons[i].click == ClickItem) {
click = ClickItem;
}
}
for (i = 0; i < LENGTH(wl_cbuttons); i++) {
if (ignoreconfmouse) break;
if (wl_cbuttons[i].click == ClickSelItem && wl_cbuttons[i].button == button) {
puts(item->text);
exit(0);
} else if (wl_cbuttons[i].click == ClickItem) {
click = ClickItem;
}
}
}
}
} else if (matches) {
x += inputw;
w = larrowWidth;
if (prev && curr->left) {
if (ex >= x && ex <= x + w) {
click = ClickLArrow;
}
}
for (item = curr; item != next; item = item->right) {
x += w;
w = MIN(TEXTW(item->text), mw - x - rarrowWidth);
if (ex >= x && ex <= x + w) {
for (i = 0; i < LENGTH(wl_buttons); i++) {
if (ignoreglobalmouse) break;
if (wl_buttons[i].click == ClickSelItem && wl_buttons[i].button == button) {
puts(item->text);
exit(0);
} else if (wl_buttons[i].click == ClickItem) {
click = ClickItem;
}
}
for (i = 0; i < LENGTH(wl_cbuttons); i++) {
if (ignoreconfmouse) break;
if (wl_cbuttons[i].click == ClickSelItem && wl_cbuttons[i].button == button) {
puts(item->text);
exit(0);
} else if (wl_cbuttons[i].click == ClickItem) {
click = ClickItem;
}
}
}
}
// right arrow
w = rarrowWidth;
x = mw - w;
if (next && ex >= x && ex <= x + w) {
click = ClickRArrow;
}
}
// go through mouse button array and run function
for (i = 0; i < LENGTH(wl_buttons); i++) {
if (ignoreglobalmouse) break;
if (click == wl_buttons[i].click && wl_buttons[i].func && wl_buttons[i].button == button)
wl_buttons[i].func(&wl_buttons[i].arg);
}
// go through mouse config array and run function
for (i = 0; i < LENGTH(wl_cbuttons); i++) {
if (ignoreconfmouse) break;
if (click == wl_cbuttons[i].click && wl_cbuttons[i].func && wl_cbuttons[i].button == button)
wl_cbuttons[i].func(&wl_cbuttons[i].arg);
}
}
void pointer_motion_handler(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) {
mouse_x = wl_fixed_to_int(x);
mouse_y = wl_fixed_to_int(y);
}
void pointer_button_handler(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
if (state != WL_POINTER_BUTTON_STATE_PRESSED) {
return; // We don't want a release event to count as a click, only the initial press.
}
buttonpress_wl(button, mouse_x, mouse_y);
}
void seat_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps) {
struct state *state = data;
if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
state->keyboard = wl_seat_get_keyboard(seat);
state->pointer = wl_seat_get_pointer(seat);
wl_keyboard_add_listener(state->keyboard, &keyboard_listener, state);
wl_pointer_add_listener(state->pointer, &pointer_listener, state);
}
}
void output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char *make, const char *model, int32_t output_transform) {
output_physical_width = physical_width;
output_physical_height = physical_height;
}
void output_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
output_width = width;
output_height = height;
}
void output_scale(void *data, struct wl_output *wl_output, int32_t factor) {
struct output *output = data;
output->scale = factor;
}
void output_name(void *data, struct wl_output *wl_output, const char *name) {
struct output *output = data;
struct state *state = output->state;
char *outname = state->output_name;
if (!state->output && outname && strcmp(outname, name) == 0) {
state->output = output;
}
}
void layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t width, uint32_t height) {
zwlr_layer_surface_v1_ack_configure(surface, serial);
}
void layer_surface_closed(void *data, struct zwlr_layer_surface_v1 *surface) {
cleanup();
exit(0);
}
void zero() {
// Nothing.
}
void draw_sf(struct state *state) {
if (!allow_draw) { // No drawing if disabled
return;
}
// create buffer to draw on
state->buffer = create_buffer(state);
if (drw == NULL) {
die("spmenu: drw == NULL");
}
if (state->buffer == NULL) {
die("state->buffer == null");
}
drw_create_surface_wl(drw, state->data, state->width, state->height);
drawmenu_layer();
wl_surface_set_buffer_scale(state->surface, 1);
wl_surface_attach(state->surface, state->buffer, 0, 0);
wl_surface_damage(state->surface, 0, 0, state->width, state->height);
wl_surface_commit(state->surface);
}
void global_handler(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) {
struct state *state = data;
if (strcmp(interface, wl_compositor_interface.name) == 0) {
state->compositor = wl_registry_bind(registry, name,
&wl_compositor_interface, 4);
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
state->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
} else if (strcmp(interface, wl_seat_interface.name) == 0 && has_keys) {
struct wl_seat *seat = wl_registry_bind(registry, name,
&wl_seat_interface, 4);
wl_seat_add_listener(seat, &seat_listener, state);
} else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
state->layer_shell = wl_registry_bind(registry, name,
&zwlr_layer_shell_v1_interface, 1);
} else if (strcmp(interface, wl_output_interface.name) == 0) {
struct output *output = calloc(1, sizeof(struct output));
output->output = wl_registry_bind(registry, name,
&wl_output_interface, 4);
output->state = state;
output->scale = 1;
wl_output_set_user_data(output->output, output);
wl_output_add_listener(output->output, &output_listener, output);
}
}
void surface_enter(void *data, struct wl_surface *surface, struct wl_output *wl_output) {
struct state *state = data;
state->output = wl_output_get_user_data(wl_output);
match();
draw_sf(state);
}
int roundtrip(struct state *state) {
if (wl_display_roundtrip(state->display)) {
return 0;
} else {
return 1;
}
}
/* If this function returns 1, something went wrong.
* This may be that the user is using X11, or a compositor like Mutter.
* In this case, it may be a good idea to fall back to X11.
*/
int init_disp(struct state *state) {
state->display = wl_display_connect(NULL);
// Open display
if (!state->display) {
return 1;
} else {
no_display = 0;
}
struct wl_registry *registry = wl_display_get_registry(state->display);
wl_registry_add_listener(registry, &registry_listener, state);
wl_display_roundtrip(state->display);
assert(state->compositor != NULL);
assert(state->layer_shell != NULL);
assert(state->shm != NULL);
wl_display_roundtrip(state->display);
if (state->output_name && !state->output) {
return 1;
}
return 0;
}
void resizeclient_wl(struct state *state) {
struct item *item;
int omh = mh;
int ic = 0;
// walk through all items
for (item = items; item && item->text; item++)
ic++;
bh = MAX(drw->font->h, drw->font->h + 2 + lineheight);
lines = MIN(ic, MAX(lines, 0));
reallines = lines;
mh = (lines + 1) * bh + 2 * menumarginv;
if (mh == omh) {
return;
}
// why have an empty line? when there's nothing to draw there anyway?
if (hideprompt && hideinput && hidemode && hidematchcount)
mh += bh;
state->width = mw;
state->height = mh;
state->buffer = create_buffer(state);
if (drw == NULL) {
die("spmenu: drw == NULL");
}
if (state->buffer == NULL) {
die("state->buffer == null");
}
drw_create_surface_wl(drw, state->data, state->width, state->height);
set_layer_size(state, state->width, state->height);
wl_surface_set_buffer_scale(state->surface, 1);
wl_surface_attach(state->surface, state->buffer, 0, 0);
wl_surface_damage(state->surface, 0, 0, state->width, state->height);
wl_surface_commit(state->surface);
}
/* It is advised you call this function right before calling init_disp()
* It sets up keybinds for you.
*/
int init_keys(struct state *state) {
state->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!state->xkb_context) {
return 1;
} else {
has_keys = 1;
}
state->timer = timerfd_create(CLOCK_MONOTONIC, 0);
if (state->timer < 0) {
has_keys = 0;
fprintf(stderr, "timerfd_create() failed\n");
return 1;
}
return 0;
}
int create_layer(struct state *state, char *name) {
assert(state->compositor != NULL);
state->surface = wl_compositor_create_surface(state->compositor);
assert(state->surface != NULL);
assert(state->layer_shell != NULL);
wl_surface_add_listener(state->surface, &surface_listener, state);
state->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
state->layer_shell,
state->surface,
NULL,
ZWLR_LAYER_SHELL_V1_LAYER_TOP,
name);
assert(state->layer_surface != NULL);
return 0;
}
int anchor_layer(struct state *state, int position) {
assert(state->layer_surface != NULL);
zwlr_layer_surface_v1_set_anchor(
state->layer_surface,
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
(position == 0 ? ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM :
position == 1 ? ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP :
0));
return 0;
}
int set_layer_size(struct state *state, int32_t width, int32_t height) {
assert(state->layer_surface != NULL);
zwlr_layer_surface_v1_set_size(state->layer_surface, width, height);
return 0;
}
int set_exclusive_zone(struct state *state, unsigned int val) {
assert(state->layer_surface != NULL);
zwlr_layer_surface_v1_set_exclusive_zone(state->layer_surface, val);
return 0;
}
int set_keyboard(struct state *state, int interactivity) {
assert(state->layer_surface != NULL);
zwlr_layer_surface_v1_set_keyboard_interactivity(state->layer_surface, interactivity ? true : false);
return 0;
}
int add_layer_listener(struct state *state) {
assert(state->layer_surface != NULL);
zwlr_layer_surface_v1_add_listener(state->layer_surface, &layer_surface_listener, state);
return 0;
}
int set_visible_layer(struct state *state) {
assert(state->layer_surface != NULL);
assert(state->surface != NULL);
wl_surface_commit(state->surface);
return 0;
}

204
libs/wl/wayland.h Normal file
View file

@ -0,0 +1,204 @@
/* See LICENSE file for copyright and license details. */
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdbool.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <sys/timerfd.h>
#include <assert.h>
#include <signal.h>
#include <poll.h>
#include <wayland-client.h>
#include <wayland-client-protocol.h>
#include <xkbcommon/xkbcommon.h>
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
#include "xdg-shell-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
struct output {
struct state *state;
struct wl_output *output;
int32_t scale;
};
typedef struct {
unsigned int mode;
char *modifier;
xkb_keysym_t keysym;
void (*func)(Arg *);
Arg arg;
} WlKey;
static WlKey wl_ckeys[256];
static Mouse wl_cbuttons[256];
#define WL_CtrlShift "CtrlShift"
#define WL_CtrlShiftSuper "CtrlShiftSuper"
#define WL_CtrlSuper "CtrlSuper"
#define WL_CtrlAlt "CtrlAlt"
#define WL_CtrlAltShift "CtrlAltShift"
#define WL_CtrlAltShiftSuper "CtrlAltShiftSuper"
#define WL_CtrlAltSuper "CtrlAltSuper"
#define WL_AltShift "AltShift"
#define WL_Shift "Shift"
#define WL_Ctrl "Ctrl"
#define WL_Alt "Alt"
#define WL_Super "Super"
#define WL_None "None"
#define WL_Left 0x110
#define WL_Right 0x111
#define WL_Middle 0x112
#define WL_Side 0x113
#define WL_Extra 0x114
#define WL_Forward 0x115
#define WL_Back 0x116
#define WL_Task 0x117
static WlKey wlhkeys[1] = { { -1, WL_CtrlAlt, XKB_KEY_Delete, quit, {0} } };
struct state {
struct output *output;
char *output_name;
struct wl_display *display;
struct wl_compositor *compositor;
struct wl_shm *shm;
struct wl_seat *seat;
struct wl_keyboard *keyboard;
struct wl_pointer *pointer;
struct wl_surface *surface;
struct zwlr_layer_shell_v1 *layer_shell;
struct zwlr_layer_surface_v1 *layer_surface;
int width;
int height;
/* Taken from wmenu */
int timer;
int delay;
int period;
struct xkb_context *xkb_context;
struct xkb_keymap *xkb_keymap;
struct xkb_state *xkb_state;
enum wl_keyboard_key_state repeat_key_state;
xkb_keysym_t repeat_sym;
void *data;
struct wl_buffer *buffer;
};
struct state state = { 0 };
static int output_physical_width = 0;
static int output_physical_height = 0;
static int output_width = 0;
static int output_height = 0;
static int mouse_x = 0;
static int mouse_y = 0;
static void zero();
static void resizeclient_wl(struct state *state);
static void output_scale(void *data, struct wl_output *wl_output, int32_t factor);
static void output_name(void *data, struct wl_output *wl_output, const char *name);
static void output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char *make, const char *model, int32_t output_transform);
static void output_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh);
static void layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t width, uint32_t height);
static void layer_surface_closed(void *data, struct zwlr_layer_surface_v1 *surface);
static void draw_sf(struct state *state);
static void global_handler(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version);
static void seat_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps);
static void surface_enter(void *data, struct wl_surface *surface, struct wl_output *wl_output);
static void keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size);
static void keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t _key_state);
static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group);
static void keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay);
static void keypress_wl(struct state *state, enum wl_keyboard_key_state key_state, xkb_keysym_t sym);
static void pointer_button_handler(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
static void pointer_motion_handler(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y);
static void buttonpress_wl(uint32_t button, double ex, double ey);
static int is_correct_modifier(struct state *state, char *modifier);
static int roundtrip(struct state *state);
static int init_disp(struct state *state);
static int init_keys(struct state *state);
static int create_layer(struct state *state, char *name);
static int anchor_layer(struct state *state, int position);
static int set_layer_size(struct state *state, int32_t width, int32_t height);
static int set_exclusive_zone(struct state *state, unsigned int val);
static int set_keyboard(struct state *state, int interactivity);
static int add_layer_listener(struct state *state);
static int set_visible_layer(struct state *state);
/* Set to 0 if the connection was successful
* You can use this for say, X11 compatibility mode.
*/
static int no_display = 1;
/* Note that you MUST override this before calling create_layer() because
* otherwise nothing will be drawn. Do not forget to do this.
*/
static int allow_draw = 0;
/* Set automatically */
static int has_keys = 0;
/* See global_handler */
static const struct wl_registry_listener registry_listener = {
.global = global_handler,
.global_remove = zero,
};
/* See surface_enter */
static const struct wl_surface_listener surface_listener = {
.enter = surface_enter,
.leave = zero,
};
static const struct wl_keyboard_listener keyboard_listener = {
.keymap = keyboard_keymap,
.enter = zero,
.leave = zero,
.key = keyboard_key,
.modifiers = keyboard_modifiers,
.repeat_info = keyboard_repeat_info,
};
static const struct wl_pointer_listener pointer_listener = {
.enter = zero,
.leave = zero,
.motion = pointer_motion_handler,
.button = pointer_button_handler,
.axis = zero,
};
struct wl_output_listener output_listener = {
.geometry = output_geometry,
.mode = output_mode,
.done = zero,
.scale = output_scale,
.name = output_name,
.description = zero,
};
struct zwlr_layer_surface_v1_listener layer_surface_listener = {
.configure = layer_surface_configure,
.closed = layer_surface_closed,
};
struct wl_seat_listener seat_listener = {
.capabilities = seat_capabilities,
.name = zero,
};
static const struct wl_buffer_listener buffer_listener = {
.release = zero,
};

View file

@ -0,0 +1,563 @@
/* Generated by wayland-scanner 1.22.0 */
#ifndef WLR_LAYER_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H
#define WLR_LAYER_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_wlr_layer_shell_unstable_v1 The wlr_layer_shell_unstable_v1 protocol
* @section page_ifaces_wlr_layer_shell_unstable_v1 Interfaces
* - @subpage page_iface_zwlr_layer_shell_v1 - create surfaces that are layers of the desktop
* - @subpage page_iface_zwlr_layer_surface_v1 - layer metadata interface
* @section page_copyright_wlr_layer_shell_unstable_v1 Copyright
* <pre>
*
* Copyright © 2017 Drew DeVault
*
* Permission to use, copy, modify, distribute, and sell this
* software and its documentation for any purpose is hereby granted
* without fee, provided that the above copyright notice appear in
* all copies and that both that copyright notice and this permission
* notice appear in supporting documentation, and that the name of
* the copyright holders not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
* THIS SOFTWARE.
* </pre>
*/
struct wl_output;
struct wl_surface;
struct xdg_popup;
struct zwlr_layer_shell_v1;
struct zwlr_layer_surface_v1;
#ifndef ZWLR_LAYER_SHELL_V1_INTERFACE
#define ZWLR_LAYER_SHELL_V1_INTERFACE
/**
* @page page_iface_zwlr_layer_shell_v1 zwlr_layer_shell_v1
* @section page_iface_zwlr_layer_shell_v1_desc Description
*
* Clients can use this interface to assign the surface_layer role to
* wl_surfaces. Such surfaces are assigned to a "layer" of the output and
* rendered with a defined z-depth respective to each other. They may also be
* anchored to the edges and corners of a screen and specify input handling
* semantics. This interface should be suitable for the implementation of
* many desktop shell components, and a broad number of other applications
* that interact with the desktop.
* @section page_iface_zwlr_layer_shell_v1_api API
* See @ref iface_zwlr_layer_shell_v1.
*/
/**
* @defgroup iface_zwlr_layer_shell_v1 The zwlr_layer_shell_v1 interface
*
* Clients can use this interface to assign the surface_layer role to
* wl_surfaces. Such surfaces are assigned to a "layer" of the output and
* rendered with a defined z-depth respective to each other. They may also be
* anchored to the edges and corners of a screen and specify input handling
* semantics. This interface should be suitable for the implementation of
* many desktop shell components, and a broad number of other applications
* that interact with the desktop.
*/
extern const struct wl_interface zwlr_layer_shell_v1_interface;
#endif
#ifndef ZWLR_LAYER_SURFACE_V1_INTERFACE
#define ZWLR_LAYER_SURFACE_V1_INTERFACE
/**
* @page page_iface_zwlr_layer_surface_v1 zwlr_layer_surface_v1
* @section page_iface_zwlr_layer_surface_v1_desc Description
*
* An interface that may be implemented by a wl_surface, for surfaces that
* are designed to be rendered as a layer of a stacked desktop-like
* environment.
*
* Layer surface state (size, anchor, exclusive zone, margin, interactivity)
* is double-buffered, and will be applied at the time wl_surface.commit of
* the corresponding wl_surface is called.
* @section page_iface_zwlr_layer_surface_v1_api API
* See @ref iface_zwlr_layer_surface_v1.
*/
/**
* @defgroup iface_zwlr_layer_surface_v1 The zwlr_layer_surface_v1 interface
*
* An interface that may be implemented by a wl_surface, for surfaces that
* are designed to be rendered as a layer of a stacked desktop-like
* environment.
*
* Layer surface state (size, anchor, exclusive zone, margin, interactivity)
* is double-buffered, and will be applied at the time wl_surface.commit of
* the corresponding wl_surface is called.
*/
extern const struct wl_interface zwlr_layer_surface_v1_interface;
#endif
#ifndef ZWLR_LAYER_SHELL_V1_ERROR_ENUM
#define ZWLR_LAYER_SHELL_V1_ERROR_ENUM
enum zwlr_layer_shell_v1_error {
/**
* wl_surface has another role
*/
ZWLR_LAYER_SHELL_V1_ERROR_ROLE = 0,
/**
* layer value is invalid
*/
ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER = 1,
/**
* wl_surface has a buffer attached or committed
*/
ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED = 2,
};
#endif /* ZWLR_LAYER_SHELL_V1_ERROR_ENUM */
#ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM
#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM
/**
* @ingroup iface_zwlr_layer_shell_v1
* available layers for surfaces
*
* These values indicate which layers a surface can be rendered in. They
* are ordered by z depth, bottom-most first. Traditional shell surfaces
* will typically be rendered between the bottom and top layers.
* Fullscreen shell surfaces are typically rendered at the top layer.
* Multiple surfaces can share a single layer, and ordering within a
* single layer is undefined.
*/
enum zwlr_layer_shell_v1_layer {
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0,
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1,
ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2,
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3,
};
#endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */
#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE 0
/**
* @ingroup iface_zwlr_layer_shell_v1
*/
#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE_SINCE_VERSION 1
/** @ingroup iface_zwlr_layer_shell_v1 */
static inline void
zwlr_layer_shell_v1_set_user_data(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwlr_layer_shell_v1, user_data);
}
/** @ingroup iface_zwlr_layer_shell_v1 */
static inline void *
zwlr_layer_shell_v1_get_user_data(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwlr_layer_shell_v1);
}
static inline uint32_t
zwlr_layer_shell_v1_get_version(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwlr_layer_shell_v1);
}
/** @ingroup iface_zwlr_layer_shell_v1 */
static inline void
zwlr_layer_shell_v1_destroy(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1)
{
wl_proxy_destroy((struct wl_proxy *) zwlr_layer_shell_v1);
}
/**
* @ingroup iface_zwlr_layer_shell_v1
*
* Create a layer surface for an existing surface. This assigns the role of
* layer_surface, or raises a protocol error if another role is already
* assigned.
*
* Creating a layer surface from a wl_surface which has a buffer attached
* or committed is a client error, and any attempts by a client to attach
* or manipulate a buffer prior to the first layer_surface.configure call
* must also be treated as errors.
*
* You may pass NULL for output to allow the compositor to decide which
* output to use. Generally this will be the one that the user most
* recently interacted with.
*
* Clients can specify a namespace that defines the purpose of the layer
* surface.
*/
static inline struct zwlr_layer_surface_v1 *
zwlr_layer_shell_v1_get_layer_surface(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1, struct wl_surface *surface, struct wl_output *output, uint32_t layer, const char *namespace)
{
struct wl_proxy *id;
id = wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_shell_v1,
ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE, &zwlr_layer_surface_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_shell_v1), 0, NULL, surface, output, layer, namespace);
return (struct zwlr_layer_surface_v1 *) id;
}
#ifndef ZWLR_LAYER_SURFACE_V1_ERROR_ENUM
#define ZWLR_LAYER_SURFACE_V1_ERROR_ENUM
enum zwlr_layer_surface_v1_error {
/**
* provided surface state is invalid
*/
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE = 0,
/**
* size is invalid
*/
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE = 1,
/**
* anchor bitfield is invalid
*/
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR = 2,
};
#endif /* ZWLR_LAYER_SURFACE_V1_ERROR_ENUM */
#ifndef ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM
#define ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM
enum zwlr_layer_surface_v1_anchor {
/**
* the top edge of the anchor rectangle
*/
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP = 1,
/**
* the bottom edge of the anchor rectangle
*/
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM = 2,
/**
* the left edge of the anchor rectangle
*/
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT = 4,
/**
* the right edge of the anchor rectangle
*/
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT = 8,
};
#endif /* ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM */
/**
* @ingroup iface_zwlr_layer_surface_v1
* @struct zwlr_layer_surface_v1_listener
*/
struct zwlr_layer_surface_v1_listener {
/**
* suggest a surface change
*
* The configure event asks the client to resize its surface.
*
* Clients should arrange their surface for the new states, and
* then send an ack_configure request with the serial sent in this
* configure event at some point before committing the new surface.
*
* The client is free to dismiss all but the last configure event
* it received.
*
* The width and height arguments specify the size of the window in
* surface-local coordinates.
*
* The size is a hint, in the sense that the client is free to
* ignore it if it doesn't resize, pick a smaller size (to satisfy
* aspect ratio or resize in steps of NxM pixels). If the client
* picks a smaller size and is anchored to two opposite anchors
* (e.g. 'top' and 'bottom'), the surface will be centered on this
* axis.
*
* If the width or height arguments are zero, it means the client
* should decide its own window dimension.
*/
void (*configure)(void *data,
struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1,
uint32_t serial,
uint32_t width,
uint32_t height);
/**
* surface should be closed
*
* The closed event is sent by the compositor when the surface
* will no longer be shown. The output may have been destroyed or
* the user may have asked for it to be removed. Further changes to
* the surface will be ignored. The client should destroy the
* resource after receiving this event, and create a new surface if
* they so choose.
*/
void (*closed)(void *data,
struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1);
};
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
static inline int
zwlr_layer_surface_v1_add_listener(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1,
const struct zwlr_layer_surface_v1_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) zwlr_layer_surface_v1,
(void (**)(void)) listener, data);
}
#define ZWLR_LAYER_SURFACE_V1_SET_SIZE 0
#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR 1
#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE 2
#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN 3
#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY 4
#define ZWLR_LAYER_SURFACE_V1_GET_POPUP 5
#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE 6
#define ZWLR_LAYER_SURFACE_V1_DESTROY 7
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_CONFIGURE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_CLOSED_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_SIZE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_GET_POPUP_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_DESTROY_SINCE_VERSION 1
/** @ingroup iface_zwlr_layer_surface_v1 */
static inline void
zwlr_layer_surface_v1_set_user_data(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwlr_layer_surface_v1, user_data);
}
/** @ingroup iface_zwlr_layer_surface_v1 */
static inline void *
zwlr_layer_surface_v1_get_user_data(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwlr_layer_surface_v1);
}
static inline uint32_t
zwlr_layer_surface_v1_get_version(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Sets the size of the surface in surface-local coordinates. The
* compositor will display the surface centered with respect to its
* anchors.
*
* If you pass 0 for either value, the compositor will assign it and
* inform you of the assignment in the configure event. You must set your
* anchor to opposite edges in the dimensions you omit; not doing so is a
* protocol error. Both values are 0 by default.
*
* Size is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_size(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t width, uint32_t height)
{
wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, width, height);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Requests that the compositor anchor the surface to the specified edges
* and corners. If two orthoginal edges are specified (e.g. 'top' and
* 'left'), then the anchor point will be the intersection of the edges
* (e.g. the top left corner of the output); otherwise the anchor point
* will be centered on that edge, or in the center if none is specified.
*
* Anchor is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_anchor(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t anchor)
{
wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_ANCHOR, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, anchor);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Requests that the compositor avoids occluding an area of the surface
* with other surfaces. The compositor's use of this information is
* implementation-dependent - do not assume that this region will not
* actually be occluded.
*
* A positive value is only meaningful if the surface is anchored to an
* edge, rather than a corner. The zone is the number of surface-local
* coordinates from the edge that are considered exclusive.
*
* Surfaces that do not wish to have an exclusive zone may instead specify
* how they should interact with surfaces that do. If set to zero, the
* surface indicates that it would like to be moved to avoid occluding
* surfaces with a positive excluzive zone. If set to -1, the surface
* indicates that it would not like to be moved to accommodate for other
* surfaces, and the compositor should extend it all the way to the edges
* it is anchored to.
*
* For example, a panel might set its exclusive zone to 10, so that
* maximized shell surfaces are not shown on top of it. A notification
* might set its exclusive zone to 0, so that it is moved to avoid
* occluding the panel, but shell surfaces are shown underneath it. A
* wallpaper or lock screen might set their exclusive zone to -1, so that
* they stretch below or over the panel.
*
* The default value is 0.
*
* Exclusive zone is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_exclusive_zone(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, int32_t zone)
{
wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, zone);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Requests that the surface be placed some distance away from the anchor
* point on the output, in surface-local coordinates. Setting this value
* for edges you are not anchored to has no effect.
*
* The exclusive zone includes the margin.
*
* Margin is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_margin(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, int32_t top, int32_t right, int32_t bottom, int32_t left)
{
wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_MARGIN, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, top, right, bottom, left);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Set to 1 to request that the seat send keyboard events to this layer
* surface. For layers below the shell surface layer, the seat will use
* normal focus semantics. For layers above the shell surface layers, the
* seat will always give exclusive keyboard focus to the top-most layer
* which has keyboard interactivity set to true.
*
* Layer surfaces receive pointer, touch, and tablet events normally. If
* you do not want to receive them, set the input region on your surface
* to an empty region.
*
* Events is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_keyboard_interactivity(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t keyboard_interactivity)
{
wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, keyboard_interactivity);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* This assigns an xdg_popup's parent to this layer_surface. This popup
* should have been created via xdg_surface::get_popup with the parent set
* to NULL, and this request must be invoked before committing the popup's
* initial state.
*
* See the documentation of xdg_popup for more details about what an
* xdg_popup is and how it is used.
*/
static inline void
zwlr_layer_surface_v1_get_popup(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, struct xdg_popup *popup)
{
wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_GET_POPUP, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, popup);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* When a configure event is received, if a client commits the
* surface in response to the configure event, then the client
* must make an ack_configure request sometime before the commit
* request, passing along the serial of the configure event.
*
* If the client receives multiple configure events before it
* can respond to one, it only has to ack the last configure event.
*
* A client is not required to commit immediately after sending
* an ack_configure request - it may even ack_configure several times
* before its next surface commit.
*
* A client may send multiple ack_configure requests before committing, but
* only the last request sent before a commit indicates which configure
* event the client really is responding to.
*/
static inline void
zwlr_layer_surface_v1_ack_configure(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t serial)
{
wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, serial);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* This request destroys the layer surface.
*/
static inline void
zwlr_layer_surface_v1_destroy(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
{
wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), WL_MARSHAL_FLAG_DESTROY);
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,81 @@
/* Generated by wayland-scanner 1.22.0 */
/*
* Copyright © 2017 Drew DeVault
*
* Permission to use, copy, modify, distribute, and sell this
* software and its documentation for any purpose is hereby granted
* without fee, provided that the above copyright notice appear in
* all copies and that both that copyright notice and this permission
* notice appear in supporting documentation, and that the name of
* the copyright holders not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
* THIS SOFTWARE.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface zwlr_layer_surface_v1_interface;
static const struct wl_interface *wlr_layer_shell_unstable_v1_types[] = {
NULL,
NULL,
NULL,
NULL,
&zwlr_layer_surface_v1_interface,
&wl_surface_interface,
&wl_output_interface,
NULL,
NULL,
&xdg_popup_interface,
};
static const struct wl_message zwlr_layer_shell_v1_requests[] = {
{ "get_layer_surface", "no?ous", wlr_layer_shell_unstable_v1_types + 4 },
};
WL_EXPORT const struct wl_interface zwlr_layer_shell_v1_interface = {
"zwlr_layer_shell_v1", 1,
1, zwlr_layer_shell_v1_requests,
0, NULL,
};
static const struct wl_message zwlr_layer_surface_v1_requests[] = {
{ "set_size", "uu", wlr_layer_shell_unstable_v1_types + 0 },
{ "set_anchor", "u", wlr_layer_shell_unstable_v1_types + 0 },
{ "set_exclusive_zone", "i", wlr_layer_shell_unstable_v1_types + 0 },
{ "set_margin", "iiii", wlr_layer_shell_unstable_v1_types + 0 },
{ "set_keyboard_interactivity", "u", wlr_layer_shell_unstable_v1_types + 0 },
{ "get_popup", "o", wlr_layer_shell_unstable_v1_types + 9 },
{ "ack_configure", "u", wlr_layer_shell_unstable_v1_types + 0 },
{ "destroy", "", wlr_layer_shell_unstable_v1_types + 0 },
};
static const struct wl_message zwlr_layer_surface_v1_events[] = {
{ "configure", "uuu", wlr_layer_shell_unstable_v1_types + 0 },
{ "closed", "", wlr_layer_shell_unstable_v1_types + 0 },
};
WL_EXPORT const struct wl_interface zwlr_layer_surface_v1_interface = {
"zwlr_layer_surface_v1", 1,
8, zwlr_layer_surface_v1_requests,
2, zwlr_layer_surface_v1_events,
};

View file

@ -0,0 +1,414 @@
/* Generated by wayland-scanner 1.22.0 */
#ifndef XDG_OUTPUT_UNSTABLE_V1_CLIENT_PROTOCOL_H
#define XDG_OUTPUT_UNSTABLE_V1_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_xdg_output_unstable_v1 The xdg_output_unstable_v1 protocol
* Protocol to describe output regions
*
* @section page_desc_xdg_output_unstable_v1 Description
*
* This protocol aims at describing outputs in a way which is more in line
* with the concept of an output on desktop oriented systems.
*
* Some information are more specific to the concept of an output for
* a desktop oriented system and may not make sense in other applications,
* such as IVI systems for example.
*
* Typically, the global compositor space on a desktop system is made of
* a contiguous or overlapping set of rectangular regions.
*
* The logical_position and logical_size events defined in this protocol
* might provide information identical to their counterparts already
* available from wl_output, in which case the information provided by this
* protocol should be preferred to their equivalent in wl_output. The goal is
* to move the desktop specific concepts (such as output location within the
* global compositor space, etc.) out of the core wl_output protocol.
*
* Warning! The protocol described in this file is experimental and
* backward incompatible changes may be made. Backward compatible
* changes may be added together with the corresponding interface
* version bump.
* Backward incompatible changes are done by bumping the version
* number in the protocol and interface names and resetting the
* interface version. Once the protocol is to be declared stable,
* the 'z' prefix and the version number in the protocol and
* interface names are removed and the interface version number is
* reset.
*
* @section page_ifaces_xdg_output_unstable_v1 Interfaces
* - @subpage page_iface_zxdg_output_manager_v1 - manage xdg_output objects
* - @subpage page_iface_zxdg_output_v1 - compositor logical output region
* @section page_copyright_xdg_output_unstable_v1 Copyright
* <pre>
*
* Copyright © 2017 Red Hat Inc.
*
* 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 (including the next
* paragraph) 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.
* </pre>
*/
struct wl_output;
struct zxdg_output_manager_v1;
struct zxdg_output_v1;
#ifndef ZXDG_OUTPUT_MANAGER_V1_INTERFACE
#define ZXDG_OUTPUT_MANAGER_V1_INTERFACE
/**
* @page page_iface_zxdg_output_manager_v1 zxdg_output_manager_v1
* @section page_iface_zxdg_output_manager_v1_desc Description
*
* A global factory interface for xdg_output objects.
* @section page_iface_zxdg_output_manager_v1_api API
* See @ref iface_zxdg_output_manager_v1.
*/
/**
* @defgroup iface_zxdg_output_manager_v1 The zxdg_output_manager_v1 interface
*
* A global factory interface for xdg_output objects.
*/
extern const struct wl_interface zxdg_output_manager_v1_interface;
#endif
#ifndef ZXDG_OUTPUT_V1_INTERFACE
#define ZXDG_OUTPUT_V1_INTERFACE
/**
* @page page_iface_zxdg_output_v1 zxdg_output_v1
* @section page_iface_zxdg_output_v1_desc Description
*
* An xdg_output describes part of the compositor geometry.
*
* This typically corresponds to a monitor that displays part of the
* compositor space.
*
* For objects version 3 onwards, after all xdg_output properties have been
* sent (when the object is created and when properties are updated), a
* wl_output.done event is sent. This allows changes to the output
* properties to be seen as atomic, even if they happen via multiple events.
* @section page_iface_zxdg_output_v1_api API
* See @ref iface_zxdg_output_v1.
*/
/**
* @defgroup iface_zxdg_output_v1 The zxdg_output_v1 interface
*
* An xdg_output describes part of the compositor geometry.
*
* This typically corresponds to a monitor that displays part of the
* compositor space.
*
* For objects version 3 onwards, after all xdg_output properties have been
* sent (when the object is created and when properties are updated), a
* wl_output.done event is sent. This allows changes to the output
* properties to be seen as atomic, even if they happen via multiple events.
*/
extern const struct wl_interface zxdg_output_v1_interface;
#endif
#define ZXDG_OUTPUT_MANAGER_V1_DESTROY 0
#define ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT 1
/**
* @ingroup iface_zxdg_output_manager_v1
*/
#define ZXDG_OUTPUT_MANAGER_V1_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_output_manager_v1
*/
#define ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT_SINCE_VERSION 1
/** @ingroup iface_zxdg_output_manager_v1 */
static inline void
zxdg_output_manager_v1_set_user_data(struct zxdg_output_manager_v1 *zxdg_output_manager_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zxdg_output_manager_v1, user_data);
}
/** @ingroup iface_zxdg_output_manager_v1 */
static inline void *
zxdg_output_manager_v1_get_user_data(struct zxdg_output_manager_v1 *zxdg_output_manager_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zxdg_output_manager_v1);
}
static inline uint32_t
zxdg_output_manager_v1_get_version(struct zxdg_output_manager_v1 *zxdg_output_manager_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zxdg_output_manager_v1);
}
/**
* @ingroup iface_zxdg_output_manager_v1
*
* Using this request a client can tell the server that it is not
* going to use the xdg_output_manager object anymore.
*
* Any objects already created through this instance are not affected.
*/
static inline void
zxdg_output_manager_v1_destroy(struct zxdg_output_manager_v1 *zxdg_output_manager_v1)
{
wl_proxy_marshal_flags((struct wl_proxy *) zxdg_output_manager_v1,
ZXDG_OUTPUT_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_output_manager_v1), WL_MARSHAL_FLAG_DESTROY);
}
/**
* @ingroup iface_zxdg_output_manager_v1
*
* This creates a new xdg_output object for the given wl_output.
*/
static inline struct zxdg_output_v1 *
zxdg_output_manager_v1_get_xdg_output(struct zxdg_output_manager_v1 *zxdg_output_manager_v1, struct wl_output *output)
{
struct wl_proxy *id;
id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_output_manager_v1,
ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT, &zxdg_output_v1_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_output_manager_v1), 0, NULL, output);
return (struct zxdg_output_v1 *) id;
}
/**
* @ingroup iface_zxdg_output_v1
* @struct zxdg_output_v1_listener
*/
struct zxdg_output_v1_listener {
/**
* position of the output within the global compositor space
*
* The position event describes the location of the wl_output
* within the global compositor space.
*
* The logical_position event is sent after creating an xdg_output
* (see xdg_output_manager.get_xdg_output) and whenever the
* location of the output changes within the global compositor
* space.
* @param x x position within the global compositor space
* @param y y position within the global compositor space
*/
void (*logical_position)(void *data,
struct zxdg_output_v1 *zxdg_output_v1,
int32_t x,
int32_t y);
/**
* size of the output in the global compositor space
*
* The logical_size event describes the size of the output in the
* global compositor space.
*
* Most regular Wayland clients should not pay attention to the
* logical size and would rather rely on xdg_shell interfaces.
*
* Some clients such as Xwayland, however, need this to configure
* their surfaces in the global compositor space as the compositor
* may apply a different scale from what is advertised by the
* output scaling property (to achieve fractional scaling, for
* example).
*
* For example, for a wl_output mode 3840×2160 and a scale factor
* 2:
*
* - A compositor not scaling the monitor viewport in its
* compositing space will advertise a logical size of 3840×2160,
*
* - A compositor scaling the monitor viewport with scale factor 2
* will advertise a logical size of 1920×1080,
*
* - A compositor scaling the monitor viewport using a fractional
* scale of 1.5 will advertise a logical size of 2560×1440.
*
* For example, for a wl_output mode 1920×1080 and a 90 degree
* rotation, the compositor will advertise a logical size of
* 1080x1920.
*
* The logical_size event is sent after creating an xdg_output (see
* xdg_output_manager.get_xdg_output) and whenever the logical size
* of the output changes, either as a result of a change in the
* applied scale or because of a change in the corresponding output
* mode(see wl_output.mode) or transform (see wl_output.transform).
* @param width width in global compositor space
* @param height height in global compositor space
*/
void (*logical_size)(void *data,
struct zxdg_output_v1 *zxdg_output_v1,
int32_t width,
int32_t height);
/**
* all information about the output have been sent
*
* This event is sent after all other properties of an xdg_output
* have been sent.
*
* This allows changes to the xdg_output properties to be seen as
* atomic, even if they happen via multiple events.
*
* For objects version 3 onwards, this event is deprecated.
* Compositors are not required to send it anymore and must send
* wl_output.done instead.
*/
void (*done)(void *data,
struct zxdg_output_v1 *zxdg_output_v1);
/**
* name of this output
*
* Many compositors will assign names to their outputs, show them
* to the user, allow them to be configured by name, etc. The
* client may wish to know this name as well to offer the user
* similar behaviors.
*
* The naming convention is compositor defined, but limited to
* alphanumeric characters and dashes (-). Each name is unique
* among all wl_output globals, but if a wl_output global is
* destroyed the same name may be reused later. The names will also
* remain consistent across sessions with the same hardware and
* software configuration.
*
* Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc.
* However, do not assume that the name is a reflection of an
* underlying DRM connector, X11 connection, etc.
*
* The name event is sent after creating an xdg_output (see
* xdg_output_manager.get_xdg_output). This event is only sent once
* per xdg_output, and the name does not change over the lifetime
* of the wl_output global.
*
* This event is deprecated, instead clients should use
* wl_output.name. Compositors must still support this event.
* @param name output name
* @since 2
*/
void (*name)(void *data,
struct zxdg_output_v1 *zxdg_output_v1,
const char *name);
/**
* human-readable description of this output
*
* Many compositors can produce human-readable descriptions of
* their outputs. The client may wish to know this description as
* well, to communicate the user for various purposes.
*
* The description is a UTF-8 string with no convention defined for
* its contents. Examples might include 'Foocorp 11" Display' or
* 'Virtual X11 output via :1'.
*
* The description event is sent after creating an xdg_output (see
* xdg_output_manager.get_xdg_output) and whenever the description
* changes. The description is optional, and may not be sent at
* all.
*
* For objects of version 2 and lower, this event is only sent once
* per xdg_output, and the description does not change over the
* lifetime of the wl_output global.
*
* This event is deprecated, instead clients should use
* wl_output.description. Compositors must still support this
* event.
* @param description output description
* @since 2
*/
void (*description)(void *data,
struct zxdg_output_v1 *zxdg_output_v1,
const char *description);
};
/**
* @ingroup iface_zxdg_output_v1
*/
static inline int
zxdg_output_v1_add_listener(struct zxdg_output_v1 *zxdg_output_v1,
const struct zxdg_output_v1_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) zxdg_output_v1,
(void (**)(void)) listener, data);
}
#define ZXDG_OUTPUT_V1_DESTROY 0
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_LOGICAL_POSITION_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_LOGICAL_SIZE_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_DONE_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_NAME_SINCE_VERSION 2
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION 2
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_DESTROY_SINCE_VERSION 1
/** @ingroup iface_zxdg_output_v1 */
static inline void
zxdg_output_v1_set_user_data(struct zxdg_output_v1 *zxdg_output_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zxdg_output_v1, user_data);
}
/** @ingroup iface_zxdg_output_v1 */
static inline void *
zxdg_output_v1_get_user_data(struct zxdg_output_v1 *zxdg_output_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zxdg_output_v1);
}
static inline uint32_t
zxdg_output_v1_get_version(struct zxdg_output_v1 *zxdg_output_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zxdg_output_v1);
}
/**
* @ingroup iface_zxdg_output_v1
*
* Using this request a client can tell the server that it is not
* going to use the xdg_output object anymore.
*/
static inline void
zxdg_output_v1_destroy(struct zxdg_output_v1 *zxdg_output_v1)
{
wl_proxy_marshal_flags((struct wl_proxy *) zxdg_output_v1,
ZXDG_OUTPUT_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_output_v1), WL_MARSHAL_FLAG_DESTROY);
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,68 @@
/* Generated by wayland-scanner 1.22.0 */
/*
* Copyright © 2017 Red Hat Inc.
*
* 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 (including the next
* paragraph) 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.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface zxdg_output_v1_interface;
static const struct wl_interface *xdg_output_unstable_v1_types[] = {
NULL,
NULL,
&zxdg_output_v1_interface,
&wl_output_interface,
};
static const struct wl_message zxdg_output_manager_v1_requests[] = {
{ "destroy", "", xdg_output_unstable_v1_types + 0 },
{ "get_xdg_output", "no", xdg_output_unstable_v1_types + 2 },
};
WL_EXPORT const struct wl_interface zxdg_output_manager_v1_interface = {
"zxdg_output_manager_v1", 3,
2, zxdg_output_manager_v1_requests,
0, NULL,
};
static const struct wl_message zxdg_output_v1_requests[] = {
{ "destroy", "", xdg_output_unstable_v1_types + 0 },
};
static const struct wl_message zxdg_output_v1_events[] = {
{ "logical_position", "ii", xdg_output_unstable_v1_types + 0 },
{ "logical_size", "ii", xdg_output_unstable_v1_types + 0 },
{ "done", "", xdg_output_unstable_v1_types + 0 },
{ "name", "2s", xdg_output_unstable_v1_types + 0 },
{ "description", "2s", xdg_output_unstable_v1_types + 0 },
};
WL_EXPORT const struct wl_interface zxdg_output_v1_interface = {
"zxdg_output_v1", 3,
1, zxdg_output_v1_requests,
5, zxdg_output_v1_events,
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,173 @@
/* Generated by wayland-scanner 1.22.0 */
/*
* Copyright © 2008-2013 Kristian Høgsberg
* Copyright © 2013 Rafael Antognolli
* Copyright © 2013 Jasper St. Pierre
* Copyright © 2010-2013 Intel Corporation
* Copyright © 2015-2017 Samsung Electronics Co., Ltd
* Copyright © 2015-2017 Red Hat Inc.
*
* 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 (including the next
* paragraph) 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.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface xdg_positioner_interface;
extern const struct wl_interface xdg_surface_interface;
extern const struct wl_interface xdg_toplevel_interface;
static const struct wl_interface *xdg_shell_types[] = {
NULL,
NULL,
NULL,
NULL,
&xdg_positioner_interface,
&xdg_surface_interface,
&wl_surface_interface,
&xdg_toplevel_interface,
&xdg_popup_interface,
&xdg_surface_interface,
&xdg_positioner_interface,
&xdg_toplevel_interface,
&wl_seat_interface,
NULL,
NULL,
NULL,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&xdg_positioner_interface,
NULL,
};
static const struct wl_message xdg_wm_base_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "create_positioner", "n", xdg_shell_types + 4 },
{ "get_xdg_surface", "no", xdg_shell_types + 5 },
{ "pong", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_wm_base_events[] = {
{ "ping", "u", xdg_shell_types + 0 },
};
WL_EXPORT const struct wl_interface xdg_wm_base_interface = {
"xdg_wm_base", 5,
4, xdg_wm_base_requests,
1, xdg_wm_base_events,
};
static const struct wl_message xdg_positioner_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_size", "ii", xdg_shell_types + 0 },
{ "set_anchor_rect", "iiii", xdg_shell_types + 0 },
{ "set_anchor", "u", xdg_shell_types + 0 },
{ "set_gravity", "u", xdg_shell_types + 0 },
{ "set_constraint_adjustment", "u", xdg_shell_types + 0 },
{ "set_offset", "ii", xdg_shell_types + 0 },
{ "set_reactive", "3", xdg_shell_types + 0 },
{ "set_parent_size", "3ii", xdg_shell_types + 0 },
{ "set_parent_configure", "3u", xdg_shell_types + 0 },
};
WL_EXPORT const struct wl_interface xdg_positioner_interface = {
"xdg_positioner", 5,
10, xdg_positioner_requests,
0, NULL,
};
static const struct wl_message xdg_surface_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "get_toplevel", "n", xdg_shell_types + 7 },
{ "get_popup", "n?oo", xdg_shell_types + 8 },
{ "set_window_geometry", "iiii", xdg_shell_types + 0 },
{ "ack_configure", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_surface_events[] = {
{ "configure", "u", xdg_shell_types + 0 },
};
WL_EXPORT const struct wl_interface xdg_surface_interface = {
"xdg_surface", 5,
5, xdg_surface_requests,
1, xdg_surface_events,
};
static const struct wl_message xdg_toplevel_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_parent", "?o", xdg_shell_types + 11 },
{ "set_title", "s", xdg_shell_types + 0 },
{ "set_app_id", "s", xdg_shell_types + 0 },
{ "show_window_menu", "ouii", xdg_shell_types + 12 },
{ "move", "ou", xdg_shell_types + 16 },
{ "resize", "ouu", xdg_shell_types + 18 },
{ "set_max_size", "ii", xdg_shell_types + 0 },
{ "set_min_size", "ii", xdg_shell_types + 0 },
{ "set_maximized", "", xdg_shell_types + 0 },
{ "unset_maximized", "", xdg_shell_types + 0 },
{ "set_fullscreen", "?o", xdg_shell_types + 21 },
{ "unset_fullscreen", "", xdg_shell_types + 0 },
{ "set_minimized", "", xdg_shell_types + 0 },
};
static const struct wl_message xdg_toplevel_events[] = {
{ "configure", "iia", xdg_shell_types + 0 },
{ "close", "", xdg_shell_types + 0 },
{ "configure_bounds", "4ii", xdg_shell_types + 0 },
{ "wm_capabilities", "5a", xdg_shell_types + 0 },
};
WL_EXPORT const struct wl_interface xdg_toplevel_interface = {
"xdg_toplevel", 5,
14, xdg_toplevel_requests,
4, xdg_toplevel_events,
};
static const struct wl_message xdg_popup_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "grab", "ou", xdg_shell_types + 22 },
{ "reposition", "3ou", xdg_shell_types + 24 },
};
static const struct wl_message xdg_popup_events[] = {
{ "configure", "iiii", xdg_shell_types + 0 },
{ "popup_done", "", xdg_shell_types + 0 },
{ "repositioned", "3u", xdg_shell_types + 0 },
};
WL_EXPORT const struct wl_interface xdg_popup_interface = {
"xdg_popup", 5,
3, xdg_popup_requests,
3, xdg_popup_events,
};

View file

@ -1,18 +1,13 @@
/* See LICENSE file for copyright and license details. */
void prepare_window_size(void) {
// set horizontal and vertical padding
sp = menupaddingh;
vp = (menuposition == 1) ? menupaddingv : - menupaddingv;
void hexconv(const char *hex, unsigned short *r, unsigned short *g, unsigned short *b) {
unsigned int col;
bh = MAX(drw->font->h, drw->font->h + 2 + lineheight);
lines = MAX(lines, 0);
reallines = lines;
sscanf(hex, "#%06X", &col);
lrpad = drw->font->h + textpadding;
mh = (lines + 1) * bh + 2 * menumarginv; // lines + 1 * bh is the menu height
return;
*r = (col >> 16) & 0xFF;
*g = (col >> 8) & 0xFF;
*b = col & 0xFF;
}
void store_image_vars(void) {
@ -22,7 +17,7 @@ void store_image_vars(void) {
if (!imagew || !imageh || !imageg) {
imagew = imagewidth;
imageh = imageheight;
imagegaps = imagegaps;
imageg = imagegaps;
}
#endif
}
@ -46,28 +41,7 @@ void set_mode(void) {
}
}
void get_width(int numwidthchecks, unsigned int minstrlen, unsigned int curstrlen) {
struct item *item;
unsigned int tmp = 0;
// get accurate width
if (accuratewidth) {
for (item = items; !lines && item && item->text; ++item) {
curstrlen = strlen(item->text);
if (numwidthchecks || minstrlen < curstrlen) {
numwidthchecks = MAX(numwidthchecks - 1, 0);
minstrlen = MAX(minstrlen, curstrlen);
if ((tmp = MIN(TEXTW(item->text), mw/3) > inputw)) {
inputw = tmp;
if (tmp == mw/3)
break;
}
}
}
}
}
void create_window(int x, int y, int w, int h) {
void create_window_x11(int x, int y, int w, int h) {
XSetWindowAttributes swa;
swa.override_redirect = managed ? False : True;
@ -85,21 +59,35 @@ void create_window(int x, int y, int w, int h) {
depth, InputOutput, visual,
CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &swa);
return;
}
void set_window(void) {
void set_window_x11(void) {
XColor col;
XClassHint ch = { class, class };
unsigned short r;
unsigned short g;
unsigned short b;
hexconv(col_border, &r, &g, &b);
col.red = r << 8;
col.green = g << 8;
col.blue = b << 8;
if (!XAllocColor(dpy, cmap, &col)) {
die("spmenu: failed to allocate xcolor");
}
// set border and class
XSetWindowBorder(dpy, win, scheme[SchemeBorder][ColBg].pixel);
XSetWindowBorder(dpy, win, col.pixel);
XSetClassHint(dpy, win, &ch);
return;
}
void set_prop(void) {
void set_prop_x11(void) {
// set properties indicating what spmenu handles
clip = XInternAtom(dpy, "CLIPBOARD", False);
utf8 = XInternAtom(dpy, "UTF8_STRING", False);
@ -112,7 +100,7 @@ void set_prop(void) {
}
}
void resizeclient(void) {
void resizeclient_x11(void) {
int omh = mh;
int x, y;
#if USEXINERAMA
@ -196,7 +184,7 @@ void resizeclient(void) {
} else { // top or bottom
x = 0;
y = menuposition ? 0 : wa.height - mh - ypos;
mw = wa.width;
mw = (menuwidth > 0 ? menuwidth : wa.width);
}
}

View file

@ -1,11 +1,10 @@
/* See LICENSE file for copyright and license details. */
static void create_window(int x, int y, int w, int h);
static void get_width(int numwidthchecks, unsigned int minstrlen, unsigned int curstrlen);
static void prepare_window_size(void);
static void set_window(void);
static void set_prop(void);
static void resizeclient(void);
static void hexconv(const char *hex, unsigned short *r, unsigned short *g, unsigned short *b);
static void create_window_x11(int x, int y, int w, int h);
static void set_window_x11(void);
static void set_prop_x11(void);
static void resizeclient_x11(void);
static void store_image_vars(void);
static void set_mode(void);
static void xinitvisual(void);

View file

@ -1,5 +1,5 @@
/* See LICENSE file for copyright and license details. */
void eventloop(void) {
void eventloop_x11(void) {
XEvent ev;
int noimg = 0;
@ -14,7 +14,7 @@ void eventloop(void) {
cleanup();
exit(1);
case ButtonPress:
buttonpress(&ev);
buttonpress_x11(&ev);
noimg = 0;
break;
case MotionNotify: // currently does nothing
@ -34,7 +34,7 @@ void eventloop(void) {
fflush(stdout);
}
keypress(&ev);
keypress_x11(&ev);
noimg = 1;
break;
case SelectionNotify: // paste selection

View file

@ -1,2 +1,2 @@
/* See LICENSE file for copyright and license details. */
static void eventloop(void);
static void eventloop_x11(void);

View file

@ -1,40 +1,29 @@
/* See LICENSE file for copyright and license details. */
void setupdisplay(void) {
void setupdisplay_x11(void) {
int x, y, i;
#if USEXINERAMA
int j, di;
#endif
unsigned int du;
unsigned int minstrlen = 0, curstrlen = 0;
int numwidthchecks = 100;
Window w, dw, *dws;
XWindowAttributes wa;
#if USEXINERAMA
XineramaScreenInfo *info;
Window pw;
int a, n, area = 0;
#endif
prepare_window_size();
prepare_window_size_x11();
// resize client to image height if deemed necessary
#if USEIMAGE
if (image) resizetoimageheight(imageheight);
#endif
mh = (lines + 1) * bh + 2 * menumarginv; // lines + 1 * bh is the menu height
// set prompt width based on prompt size
promptw = (prompt && *prompt)
? pango_prompt ? TEXTWM(prompt) : TEXTW(prompt) - lrpad / 4 : 0; // prompt width
get_width(numwidthchecks, minstrlen, curstrlen);
// init xinerama screens
#if USEXINERAMA
XineramaScreenInfo *info;
Window pw;
int a, n, area = 0;
int j, di;
i = 0;
if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
XGetInputFocus(dpy, &w, &di);
@ -63,8 +52,8 @@ void setupdisplay(void) {
// calculate x/y position
if (menuposition == 2) { // centered
mw = MIN(MAX(max_textw() + promptw, minwidth), info[i].width);
x = info[i].x_org + ((info[i].width - mw) / 2);
y = info[i].y_org + ((info[i].height - mh) / 2);
x = info[i].x_org + xpos + ((info[i].width - mw) / 2);
y = info[i].y_org - ypos + ((info[i].height - mh) / 2);
} else { // top or bottom
x = info[i].x_org + xpos;
y = info[i].y_org + (menuposition ? 0 : info[i].height - mh - ypos);
@ -81,28 +70,25 @@ void setupdisplay(void) {
if (menuposition == 2) { // centered
mw = MIN(MAX(max_textw() + promptw, minwidth), wa.width);
x = (wa.width - mw) / 2;
y = (wa.height - mh) / 2;
x = (wa.width - mw) / 2 + xpos;
y = (wa.height - mh) / 2 - ypos;
} else { // top or bottom
x = 0;
y = menuposition ? 0 : wa.width - mh - ypos;
mw = wa.width;
mw = (menuwidth > 0 ? menuwidth : wa.width);
}
}
// might be faster in some instances, most of the time unnecessary
if (!accuratewidth) inputw = MIN(inputw, mw/3);
// create menu window and set properties for it
create_window(
create_window_x11(
x + sp,
y + vp - (menuposition == 1 ? 0 : menuposition == 2 ? borderwidth : borderwidth * 2),
mw - 2 * sp - borderwidth * 2,
mh
);
set_window();
set_prop();
set_window_x11();
set_prop_x11();
#if USEIMAGE
setimageopts();
@ -139,11 +125,25 @@ void setupdisplay(void) {
drawmenu();
}
Display * opendisplay(char *disp) {
void prepare_window_size_x11(void) {
sp = menupaddingh;
vp = (menuposition == 1) ? menupaddingv : - menupaddingv;
bh = MAX(drw->font->h, drw->font->h + 2 + lineheight);
lines = MAX(lines, 0);
reallines = lines;
lrpad = drw->font->h + textpadding;
mh = (lines + 1) * bh + 2 * menumarginv; // lines + 1 * bh is the menu height
return;
}
Display * opendisplay_x11(char *disp) {
return XOpenDisplay(disp);
}
void set_screen(Display *disp) {
void set_screen_x11(Display *disp) {
screen = DefaultScreen(disp);
root = RootWindow(disp, screen);
}
@ -157,11 +157,11 @@ void handle_x11(void) {
if (!XSetLocaleModifiers(""))
fputs("warning: no locale modifiers support\n", stderr);
if (!(dpy = opendisplay(NULL)))
if (!(dpy = opendisplay_x11(NULL)))
die("spmenu: cannot open display"); // failed to open display
// set screen and root window
set_screen(dpy);
set_screen_x11(dpy);
// parent window is the root window (ie. window manager) because we're not embedding
if (!embed || !(parentwin = strtol(embed, NULL, 0)))
@ -172,7 +172,7 @@ void handle_x11(void) {
}
xinitvisual(); // init visual and create drawable after
drw = drw_create(dpy, screen, root, wa.width, wa.height, visual, depth, cmap);
drw = drw_create_x11(dpy, screen, root, wa.width, wa.height, visual, depth, cmap, protocol);
}
void cleanup_x11(Display *disp) {

View file

@ -4,8 +4,9 @@ static Atom clip, utf8, types, dock;
static Display *dpy;
static Window root, parentwin, win;
static void setupdisplay(void);
static void set_screen(Display *disp);
static void setupdisplay_x11(void);
static void set_screen_x11(Display *disp);
static void handle_x11(void);
static void cleanup_x11(Display *disp);
static Display * opendisplay(char *disp);
static void prepare_window_size_x11(void);
static Display * opendisplay_x11(char *disp);

View file

@ -14,7 +14,7 @@ void updatenumlockmask(void) {
XFreeModifiermap(modmap);
}
void keypress(XEvent *e) {
void keypress_x11(XEvent *e) {
updatenumlockmask();
{
unsigned int i;
@ -73,7 +73,7 @@ void keypress(XEvent *e) {
}
}
void grabkeyboard(void) {
void grabkeyboard_x11(void) {
struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
int i;

View file

@ -17,8 +17,8 @@ typedef struct {
#define ShiftGr Mod5Mask
static void updatenumlockmask(void);
static void keypress(XEvent *e);
static void grabkeyboard(void);
static void keypress_x11(XEvent *e);
static void grabkeyboard_x11(void);
static void getcapsstate(void);
static Key ckeys[256];

View file

@ -1,6 +1,6 @@
/* See LICENSE file for copyright and license details. */
void buttonpress(XEvent *e) {
void buttonpress_x11(XEvent *e) {
struct item *item;
XButtonPressedEvent *ev = &e->xbutton;
int x = 0, y = 0, h = bh, w, item_num = 0;
@ -68,7 +68,7 @@ void buttonpress(XEvent *e) {
if (ev->y >= y && ev->y <= (y + h) && ev->x >= x && ev->x <= (x + w / columns)) {
for (i = 0; i < LENGTH(buttons); i++) {
if (ignoreglobalmouse) break;
if (buttons[i].click == ClickSelItem && buttons[i].button == ev->button && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) {
if (buttons[i].click == ClickSelItem && buttons[i].button == ev->button) {
puts(item->text);
exit(0);
} else if (buttons[i].click == ClickItem) {
@ -77,7 +77,7 @@ void buttonpress(XEvent *e) {
}
for (i = 0; i < LENGTH(cbuttons); i++) {
if (ignoreconfmouse) break;
if (cbuttons[i].click == ClickSelItem && cbuttons[i].button == ev->button && CLEANMASK(cbuttons[i].mask) == CLEANMASK(ev->state)) {
if (cbuttons[i].click == ClickSelItem && cbuttons[i].button == ev->button) {
puts(item->text);
exit(0);
} else if (cbuttons[i].click == ClickItem) {
@ -103,7 +103,7 @@ void buttonpress(XEvent *e) {
if (ev->x >= x && ev->x <= x + w) {
for (i = 0; i < LENGTH(buttons); i++) {
if (ignoreglobalmouse) break;
if (buttons[i].click == ClickSelItem && buttons[i].button == ev->button && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) {
if (buttons[i].click == ClickSelItem && buttons[i].button == ev->button) {
puts(item->text);
exit(0);
} else if (buttons[i].click == ClickItem) {
@ -112,7 +112,7 @@ void buttonpress(XEvent *e) {
}
for (i = 0; i < LENGTH(cbuttons); i++) {
if (ignoreconfmouse) break;
if (cbuttons[i].click == ClickSelItem && cbuttons[i].button == ev->button && CLEANMASK(cbuttons[i].mask) == CLEANMASK(ev->state)) {
if (cbuttons[i].click == ClickSelItem && cbuttons[i].button == ev->button) {
puts(item->text);
exit(0);
} else if (cbuttons[i].click == ClickItem) {
@ -133,16 +133,14 @@ void buttonpress(XEvent *e) {
// go through mouse button array and run function
for (i = 0; i < LENGTH(buttons); i++) {
if (ignoreglobalmouse) break;
if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button)
buttons[i].func(&buttons[i].arg);
}
// go through mouse config array and run function
for (i = 0; i < LENGTH(cbuttons); i++) {
if (ignoreconfmouse) break;
if (click == cbuttons[i].click && cbuttons[i].func && cbuttons[i].button == ev->button
&& CLEANMASK(cbuttons[i].mask) == CLEANMASK(ev->state))
if (click == cbuttons[i].click && cbuttons[i].func && cbuttons[i].button == ev->button)
cbuttons[i].func(&cbuttons[i].arg);
}
}

View file

@ -16,11 +16,10 @@ enum {
typedef struct {
unsigned int click;
unsigned int mask;
unsigned int button;
void (*func)(Arg *arg);
Arg arg;
} Mouse;
static Mouse cbuttons[256];
static void buttonpress(XEvent *e);
static void buttonpress_x11(XEvent *e);

View file

@ -120,7 +120,6 @@ ResourcePref resources[] = {
{ "selitempadding", INTEGER, &selitempadding },
{ "priitempadding", INTEGER, &priitempadding },
{ "indentitems", INTEGER, &indentitems },
{ "accuratewidth", INTEGER, &accuratewidth },
{ "alpha", INTEGER, &alpha },
{ "type", INTEGER, &type },
{ "passwd", INTEGER, &passwd },

View file

@ -1,7 +1,7 @@
project(
'spmenu',
'c',
version : '"1.2.1"',
version : '"2.0"',
default_options : ['warning_level=3']
)
@ -39,6 +39,21 @@ build_args = [
'-Wno-sign-compare',
]
if get_option('wayland')
project_dependencies += [ dependency('wayland-client') ]
project_dependencies += [ dependency('wayland-scanner') ]
project_dependencies += [ dependency('wayland-protocols') ]
project_dependencies += [ dependency('xkbcommon') ]
project_source_files += [ 'libs/wl/wlr-layer-shell-unstable-v1-client-protocol.h' ]
project_source_files += [ 'libs/wl/wlr-layer-shell-unstable-v1-protocol.c' ]
project_source_files += [ 'libs/wl/xdg-output-unstable-v1-client-protocol.h' ]
project_source_files += [ 'libs/wl/xdg-output-unstable-v1-protocol.c' ]
project_source_files += [ 'libs/wl/xdg-shell-client-protocol.h' ]
project_source_files += [ 'libs/wl/xdg-shell-protocol.c' ]
build_args += [ '-DWAYLAND' ]
run_command('scripts/make/generate-headers.sh', check : false)
endif
if get_option('imlib2') and get_option('openssl')
project_dependencies += [ dependency('imlib2') ]
project_dependencies += [ dependency('openssl') ]

View file

@ -1,3 +1,10 @@
option(
'wayland',
type : 'boolean',
value : true,
description : 'Enable Wayland support'
)
option(
'imlib2',
type : 'boolean',

22
mouse.h
View file

@ -5,10 +5,22 @@
* See LICENSE file for copyright and license details.
*/
/* Only applies to X11 */
static Mouse buttons[] = {
{ ClickInput, 0, Button1, clear, {0} },
{ ClickPrompt, 0, Button1, clear, {0} },
{ ClickMode, 0, Button1, switchmode, {0} },
{ ClickNumber, 0, Button1, viewhist, {0} },
{ ClickSelItem, 0, Button1, NULL, {0} },
{ ClickInput, Button1, clear, {0} },
{ ClickPrompt, Button1, clear, {0} },
{ ClickMode, Button1, switchmode, {0} },
{ ClickNumber, Button1, viewhist, {0} },
{ ClickSelItem, Button1, NULL, {0} },
};
/* Only applies to Wayland */
#if USEWAYLAND
static Mouse wl_buttons[] = {
{ ClickInput, WL_Left, clear, {0} },
{ ClickPrompt, WL_Left, clear, {0} },
{ ClickMode, WL_Left, switchmode, {0} },
{ ClickNumber, WL_Left, viewhist, {0} },
{ ClickSelItem, WL_Left, NULL, {0} },
};
#endif

View file

@ -6,11 +6,12 @@
/* spmenu options */
static char *class = "spmenu"; /* Class for spmenu */
static int protocol = 1; /* Protocol to try first (0: X11, 1: Wayland) */
static int fast = 0; /* Grab keyboard first */
static int xresources = 1; /* Enable .Xresources support */
static int globalcolors = 1; /* Recognize global colors (such as colors generated by Pywal) */
static int loadconfig = 1; /* Load configuration (~/.config/spmenu/spmenu.conf) on runtime */
static int loadtheme = 1; /* Load theme (~/.theme.conf or ~/.config/spmenu/theme.conf) on runtime */
static int loadtheme = 1; /* Load theme (~/.config/spmenu/theme.conf) on runtime */
static int loadbinds = 1; /* Load keybind file (~/.config/spmenu/binds.conf) on runtime */
static int mon = -1; /* Monitor to run spmenu on */
@ -19,7 +20,7 @@ static int alpha = 1; /* Enable alpha */
static int menuposition = 2; /* Position of the menu (0: Bottom, 1: Top, 2: Center */
static int menupaddingv = 0; /* Vertical padding inside the menu (in pixels) */
static int menupaddingh = 0; /* Horizontal padding inside the menu (in pixels) */
static int menuwidth = 0; /* spmenu width when setting X/Y position */
static int menuwidth = 0; /* spmenu width */
static int menumarginv = 0; /* Vertical padding around the menu */
static int menumarginh = 0; /* Horizontal padding around the menu */
static int minwidth = 1000; /* Minimum width when centered */
@ -80,7 +81,6 @@ static int sortmatches = 1; /* Sort matches (0/1) */
static int casesensitive = 0; /* Case-sensitive by default? (0/1) */
static int mark = 1; /* Enable marking items (multi selection) (0/1) */
static int preselected = 0; /* Which line should spmenu preselect? */
static int accuratewidth = 0; /* Enable accurate width. May have a performance hit if you are matching a lot of items at once */
static int fuzzy = 1; /* Whether or not to enable fuzzy matching by default */
static char *listfile = NULL; /* File to read entries from instead of stdin. NULL means read from stdin instead. */

View file

@ -0,0 +1,285 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wlr_layer_shell_unstable_v1">
<copyright>
Copyright © 2017 Drew DeVault
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="zwlr_layer_shell_v1" version="1">
<description summary="create surfaces that are layers of the desktop">
Clients can use this interface to assign the surface_layer role to
wl_surfaces. Such surfaces are assigned to a "layer" of the output and
rendered with a defined z-depth respective to each other. They may also be
anchored to the edges and corners of a screen and specify input handling
semantics. This interface should be suitable for the implementation of
many desktop shell components, and a broad number of other applications
that interact with the desktop.
</description>
<request name="get_layer_surface">
<description summary="create a layer_surface from a surface">
Create a layer surface for an existing surface. This assigns the role of
layer_surface, or raises a protocol error if another role is already
assigned.
Creating a layer surface from a wl_surface which has a buffer attached
or committed is a client error, and any attempts by a client to attach
or manipulate a buffer prior to the first layer_surface.configure call
must also be treated as errors.
You may pass NULL for output to allow the compositor to decide which
output to use. Generally this will be the one that the user most
recently interacted with.
Clients can specify a namespace that defines the purpose of the layer
surface.
</description>
<arg name="id" type="new_id" interface="zwlr_layer_surface_v1"/>
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
<arg name="layer" type="uint" enum="layer" summary="layer to add this surface to"/>
<arg name="namespace" type="string" summary="namespace for the layer surface"/>
</request>
<enum name="error">
<entry name="role" value="0" summary="wl_surface has another role"/>
<entry name="invalid_layer" value="1" summary="layer value is invalid"/>
<entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/>
</enum>
<enum name="layer">
<description summary="available layers for surfaces">
These values indicate which layers a surface can be rendered in. They
are ordered by z depth, bottom-most first. Traditional shell surfaces
will typically be rendered between the bottom and top layers.
Fullscreen shell surfaces are typically rendered at the top layer.
Multiple surfaces can share a single layer, and ordering within a
single layer is undefined.
</description>
<entry name="background" value="0"/>
<entry name="bottom" value="1"/>
<entry name="top" value="2"/>
<entry name="overlay" value="3"/>
</enum>
</interface>
<interface name="zwlr_layer_surface_v1" version="1">
<description summary="layer metadata interface">
An interface that may be implemented by a wl_surface, for surfaces that
are designed to be rendered as a layer of a stacked desktop-like
environment.
Layer surface state (size, anchor, exclusive zone, margin, interactivity)
is double-buffered, and will be applied at the time wl_surface.commit of
the corresponding wl_surface is called.
</description>
<request name="set_size">
<description summary="sets the size of the surface">
Sets the size of the surface in surface-local coordinates. The
compositor will display the surface centered with respect to its
anchors.
If you pass 0 for either value, the compositor will assign it and
inform you of the assignment in the configure event. You must set your
anchor to opposite edges in the dimensions you omit; not doing so is a
protocol error. Both values are 0 by default.
Size is double-buffered, see wl_surface.commit.
</description>
<arg name="width" type="uint"/>
<arg name="height" type="uint"/>
</request>
<request name="set_anchor">
<description summary="configures the anchor point of the surface">
Requests that the compositor anchor the surface to the specified edges
and corners. If two orthoginal edges are specified (e.g. 'top' and
'left'), then the anchor point will be the intersection of the edges
(e.g. the top left corner of the output); otherwise the anchor point
will be centered on that edge, or in the center if none is specified.
Anchor is double-buffered, see wl_surface.commit.
</description>
<arg name="anchor" type="uint" enum="anchor"/>
</request>
<request name="set_exclusive_zone">
<description summary="configures the exclusive geometry of this surface">
Requests that the compositor avoids occluding an area of the surface
with other surfaces. The compositor's use of this information is
implementation-dependent - do not assume that this region will not
actually be occluded.
A positive value is only meaningful if the surface is anchored to an
edge, rather than a corner. The zone is the number of surface-local
coordinates from the edge that are considered exclusive.
Surfaces that do not wish to have an exclusive zone may instead specify
how they should interact with surfaces that do. If set to zero, the
surface indicates that it would like to be moved to avoid occluding
surfaces with a positive excluzive zone. If set to -1, the surface
indicates that it would not like to be moved to accommodate for other
surfaces, and the compositor should extend it all the way to the edges
it is anchored to.
For example, a panel might set its exclusive zone to 10, so that
maximized shell surfaces are not shown on top of it. A notification
might set its exclusive zone to 0, so that it is moved to avoid
occluding the panel, but shell surfaces are shown underneath it. A
wallpaper or lock screen might set their exclusive zone to -1, so that
they stretch below or over the panel.
The default value is 0.
Exclusive zone is double-buffered, see wl_surface.commit.
</description>
<arg name="zone" type="int"/>
</request>
<request name="set_margin">
<description summary="sets a margin from the anchor point">
Requests that the surface be placed some distance away from the anchor
point on the output, in surface-local coordinates. Setting this value
for edges you are not anchored to has no effect.
The exclusive zone includes the margin.
Margin is double-buffered, see wl_surface.commit.
</description>
<arg name="top" type="int"/>
<arg name="right" type="int"/>
<arg name="bottom" type="int"/>
<arg name="left" type="int"/>
</request>
<request name="set_keyboard_interactivity">
<description summary="requests keyboard events">
Set to 1 to request that the seat send keyboard events to this layer
surface. For layers below the shell surface layer, the seat will use
normal focus semantics. For layers above the shell surface layers, the
seat will always give exclusive keyboard focus to the top-most layer
which has keyboard interactivity set to true.
Layer surfaces receive pointer, touch, and tablet events normally. If
you do not want to receive them, set the input region on your surface
to an empty region.
Events is double-buffered, see wl_surface.commit.
</description>
<arg name="keyboard_interactivity" type="uint"/>
</request>
<request name="get_popup">
<description summary="assign this layer_surface as an xdg_popup parent">
This assigns an xdg_popup's parent to this layer_surface. This popup
should have been created via xdg_surface::get_popup with the parent set
to NULL, and this request must be invoked before committing the popup's
initial state.
See the documentation of xdg_popup for more details about what an
xdg_popup is and how it is used.
</description>
<arg name="popup" type="object" interface="xdg_popup"/>
</request>
<request name="ack_configure">
<description summary="ack a configure event">
When a configure event is received, if a client commits the
surface in response to the configure event, then the client
must make an ack_configure request sometime before the commit
request, passing along the serial of the configure event.
If the client receives multiple configure events before it
can respond to one, it only has to ack the last configure event.
A client is not required to commit immediately after sending
an ack_configure request - it may even ack_configure several times
before its next surface commit.
A client may send multiple ack_configure requests before committing, but
only the last request sent before a commit indicates which configure
event the client really is responding to.
</description>
<arg name="serial" type="uint" summary="the serial from the configure event"/>
</request>
<request name="destroy" type="destructor">
<description summary="destroy the layer_surface">
This request destroys the layer surface.
</description>
</request>
<event name="configure">
<description summary="suggest a surface change">
The configure event asks the client to resize its surface.
Clients should arrange their surface for the new states, and then send
an ack_configure request with the serial sent in this configure event at
some point before committing the new surface.
The client is free to dismiss all but the last configure event it
received.
The width and height arguments specify the size of the window in
surface-local coordinates.
The size is a hint, in the sense that the client is free to ignore it if
it doesn't resize, pick a smaller size (to satisfy aspect ratio or
resize in steps of NxM pixels). If the client picks a smaller size and
is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the
surface will be centered on this axis.
If the width or height arguments are zero, it means the client should
decide its own window dimension.
</description>
<arg name="serial" type="uint"/>
<arg name="width" type="uint"/>
<arg name="height" type="uint"/>
</event>
<event name="closed">
<description summary="surface should be closed">
The closed event is sent by the compositor when the surface will no
longer be shown. The output may have been destroyed or the user may
have asked for it to be removed. Further changes to the surface will be
ignored. The client should destroy the resource after receiving this
event, and create a new surface if they so choose.
</description>
</event>
<enum name="error">
<entry name="invalid_surface_state" value="0" summary="provided surface state is invalid"/>
<entry name="invalid_size" value="1" summary="size is invalid"/>
<entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/>
</enum>
<enum name="anchor" bitfield="true">
<entry name="top" value="1" summary="the top edge of the anchor rectangle"/>
<entry name="bottom" value="2" summary="the bottom edge of the anchor rectangle"/>
<entry name="left" value="4" summary="the left edge of the anchor rectangle"/>
<entry name="right" value="8" summary="the right edge of the anchor rectangle"/>
</enum>
</interface>
</protocol>

View file

@ -0,0 +1,222 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="xdg_output_unstable_v1">
<copyright>
Copyright © 2017 Red Hat Inc.
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 (including the next
paragraph) 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.
</copyright>
<description summary="Protocol to describe output regions">
This protocol aims at describing outputs in a way which is more in line
with the concept of an output on desktop oriented systems.
Some information are more specific to the concept of an output for
a desktop oriented system and may not make sense in other applications,
such as IVI systems for example.
Typically, the global compositor space on a desktop system is made of
a contiguous or overlapping set of rectangular regions.
The logical_position and logical_size events defined in this protocol
might provide information identical to their counterparts already
available from wl_output, in which case the information provided by this
protocol should be preferred to their equivalent in wl_output. The goal is
to move the desktop specific concepts (such as output location within the
global compositor space, etc.) out of the core wl_output protocol.
Warning! The protocol described in this file is experimental and
backward incompatible changes may be made. Backward compatible
changes may be added together with the corresponding interface
version bump.
Backward incompatible changes are done by bumping the version
number in the protocol and interface names and resetting the
interface version. Once the protocol is to be declared stable,
the 'z' prefix and the version number in the protocol and
interface names are removed and the interface version number is
reset.
</description>
<interface name="zxdg_output_manager_v1" version="3">
<description summary="manage xdg_output objects">
A global factory interface for xdg_output objects.
</description>
<request name="destroy" type="destructor">
<description summary="destroy the xdg_output_manager object">
Using this request a client can tell the server that it is not
going to use the xdg_output_manager object anymore.
Any objects already created through this instance are not affected.
</description>
</request>
<request name="get_xdg_output">
<description summary="create an xdg output from a wl_output">
This creates a new xdg_output object for the given wl_output.
</description>
<arg name="id" type="new_id" interface="zxdg_output_v1"/>
<arg name="output" type="object" interface="wl_output"/>
</request>
</interface>
<interface name="zxdg_output_v1" version="3">
<description summary="compositor logical output region">
An xdg_output describes part of the compositor geometry.
This typically corresponds to a monitor that displays part of the
compositor space.
For objects version 3 onwards, after all xdg_output properties have been
sent (when the object is created and when properties are updated), a
wl_output.done event is sent. This allows changes to the output
properties to be seen as atomic, even if they happen via multiple events.
</description>
<request name="destroy" type="destructor">
<description summary="destroy the xdg_output object">
Using this request a client can tell the server that it is not
going to use the xdg_output object anymore.
</description>
</request>
<event name="logical_position">
<description summary="position of the output within the global compositor space">
The position event describes the location of the wl_output within
the global compositor space.
The logical_position event is sent after creating an xdg_output
(see xdg_output_manager.get_xdg_output) and whenever the location
of the output changes within the global compositor space.
</description>
<arg name="x" type="int"
summary="x position within the global compositor space"/>
<arg name="y" type="int"
summary="y position within the global compositor space"/>
</event>
<event name="logical_size">
<description summary="size of the output in the global compositor space">
The logical_size event describes the size of the output in the
global compositor space.
Most regular Wayland clients should not pay attention to the
logical size and would rather rely on xdg_shell interfaces.
Some clients such as Xwayland, however, need this to configure
their surfaces in the global compositor space as the compositor
may apply a different scale from what is advertised by the output
scaling property (to achieve fractional scaling, for example).
For example, for a wl_output mode 3840×2160 and a scale factor 2:
- A compositor not scaling the monitor viewport in its compositing space
will advertise a logical size of 3840×2160,
- A compositor scaling the monitor viewport with scale factor 2 will
advertise a logical size of 1920×1080,
- A compositor scaling the monitor viewport using a fractional scale of
1.5 will advertise a logical size of 2560×1440.
For example, for a wl_output mode 1920×1080 and a 90 degree rotation,
the compositor will advertise a logical size of 1080x1920.
The logical_size event is sent after creating an xdg_output
(see xdg_output_manager.get_xdg_output) and whenever the logical
size of the output changes, either as a result of a change in the
applied scale or because of a change in the corresponding output
mode(see wl_output.mode) or transform (see wl_output.transform).
</description>
<arg name="width" type="int"
summary="width in global compositor space"/>
<arg name="height" type="int"
summary="height in global compositor space"/>
</event>
<event name="done">
<description summary="all information about the output have been sent">
This event is sent after all other properties of an xdg_output
have been sent.
This allows changes to the xdg_output properties to be seen as
atomic, even if they happen via multiple events.
For objects version 3 onwards, this event is deprecated. Compositors
are not required to send it anymore and must send wl_output.done
instead.
</description>
</event>
<!-- Version 2 additions -->
<event name="name" since="2">
<description summary="name of this output">
Many compositors will assign names to their outputs, show them to the
user, allow them to be configured by name, etc. The client may wish to
know this name as well to offer the user similar behaviors.
The naming convention is compositor defined, but limited to
alphanumeric characters and dashes (-). Each name is unique among all
wl_output globals, but if a wl_output global is destroyed the same name
may be reused later. The names will also remain consistent across
sessions with the same hardware and software configuration.
Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do
not assume that the name is a reflection of an underlying DRM
connector, X11 connection, etc.
The name event is sent after creating an xdg_output (see
xdg_output_manager.get_xdg_output). This event is only sent once per
xdg_output, and the name does not change over the lifetime of the
wl_output global.
This event is deprecated, instead clients should use wl_output.name.
Compositors must still support this event.
</description>
<arg name="name" type="string" summary="output name"/>
</event>
<event name="description" since="2">
<description summary="human-readable description of this output">
Many compositors can produce human-readable descriptions of their
outputs. The client may wish to know this description as well, to
communicate the user for various purposes.
The description is a UTF-8 string with no convention defined for its
contents. Examples might include 'Foocorp 11" Display' or 'Virtual X11
output via :1'.
The description event is sent after creating an xdg_output (see
xdg_output_manager.get_xdg_output) and whenever the description
changes. The description is optional, and may not be sent at all.
For objects of version 2 and lower, this event is only sent once per
xdg_output, and the description does not change over the lifetime of
the wl_output global.
This event is deprecated, instead clients should use
wl_output.description. Compositors must still support this event.
</description>
<arg name="description" type="string" summary="output description"/>
</event>
</interface>
</protocol>

1361
protocols/xdg-shell.xml Normal file

File diff suppressed because it is too large Load diff

View file

@ -25,6 +25,7 @@ loadconf() {
build() {
[ ! -f "meson.build" ] && printf "meson.build does not exist.\n" && exit 1
[ "$gen_manual" != "false" ] && [ -x "$(command -v pandoc)" ] && scripts/make/generate-docs.sh
[ -z "$wayland" ] && wayland=true
cp -f meson.build meson.build.orig
@ -42,6 +43,7 @@ build() {
-Dimlib2="$imlib2" \
-Dopenssl="$openssl" \
-Dlibconfig="$libconfig" \
-Dwayland="$wayland" \
--prefix "$prefix" \
build
else
@ -52,6 +54,7 @@ build() {
-Dimlib2="$imlib2" \
-Dopenssl="$openssl" \
-Dlibconfig="$libconfig" \
-Dwayland="$wayland" \
--prefix "$prefix" \
build
fi
@ -69,6 +72,7 @@ install() {
[ "$reconfigure" = "true" ] && rm -rf build/
}
[ "$(id -u)" != "0" ] && [ "$install" != "false" ] && printf "Run as root.\n" && exit 1
check
loadconf
build

View file

@ -0,0 +1,31 @@
#!/bin/sh
[ ! -x "$(command -v wayland-scanner)" ] && exit 1
wayland-scanner \
client-header \
protocols/wlr-layer-shell-unstable-v1.xml \
libs/wl/wlr-layer-shell-unstable-v1-client-protocol.h
wayland-scanner \
client-header \
protocols/xdg-shell.xml \
libs/wl/xdg-shell-client-protocol.h
wayland-scanner \
client-header \
protocols/xdg-output-unstable-v1.xml \
libs/wl/xdg-output-unstable-v1-client-protocol.h
wayland-scanner \
public-code \
protocols/wlr-layer-shell-unstable-v1.xml \
libs/wl/wlr-layer-shell-unstable-v1-protocol.c
wayland-scanner \
public-code \
protocols/xdg-shell.xml \
libs/wl/xdg-shell-protocol.c
wayland-scanner \
public-code \
protocols/xdg-output-unstable-v1.xml \
libs/wl/xdg-output-unstable-v1-protocol.c

View file

@ -4,7 +4,7 @@ version="$(grep "version : '" meson.build | awk '{ print $3 }' | sed "s/'\"//g;
rm -f spmenu spmenu-${version}.tar.gz spmenu-${version}.PKGBUILD *.o *zst*
mkdir -p spmenu-${version}
cp -rf LICENSE meson.build meson.options *.h *.c scripts/ docs/ libs/ PKGBUILD spmenu-${version}
cp -rf LICENSE meson.build meson.options *.h *.c scripts/ docs/ libs/ protocols/ PKGBUILD spmenu-${version}
[ -f Makefile ] && cp Makefile spmenu-${version} || :
[ -f host.mk ] && cp host.mk spmenu-${version} || :
[ -f toggle.mk ] && cp toggle.mk spmenu-${version} || :

View file

@ -71,7 +71,7 @@ l[24]=y
l[25]=z
main() {
printf "${v2}s${v3}p${v4}m${v5}e${v6}n${v7}u${v8} $(spmenu -v | sed 's/spmenu-//g')\n\
printf "${v2}s${v3}p${v4}m${v5}e${v6}n${v7}u${v8} $(${RUNLAUNCHER:-spmenu} -v | sed 's/spmenu-//g')\n\
\n<big><u>Formatting</u></big>\n\n\
abcdefghijklmnopqrstuvwxyz\n\
<b>abcdefghijklmnopqrstuvwxyz</b> - b\n\
@ -153,4 +153,4 @@ printf "\n\n<big><u>The End</u></big>\n"
printf "\nIf spmenu displayed 256 colors as well as various forms of formatted text, everything works fine.\nOtherwise, please file a bug report.\n"
}
main "$@" | spmenu --no-alpha --lines 40 "$@" --columns 1 --prompt "<big>spmenu <i>test</i> <small>script</small></big>"
main "$@" | ${RUNLAUNCHER:-spmenu} --no-alpha --lines 40 "$@" --columns 1 --prompt "<big>spmenu <i>test</i> <small>script</small></big>"

View file

@ -15,13 +15,13 @@
. ftr VB CB
. ftr VBI CBI
.\}
.TH "spmenu" "1" "" "1.2.1" "fancy dynamic menu"
.TH "spmenu" "1" "" "2.0" "fancy dynamic menu"
.hy
.SH spmenu
.PP
spmenu is an X11 menu application which takes standard input, parses it,
and lets the user choose an option and sends the selected option to
standard output.
spmenu is an X11 and Wayland menu application which takes standard
input, parses it, lets the user choose an option and sends the selected
option to standard output.
.PP
In addition to this, it also serves as a run launcher through the
included shell script \f[V]spmenu_run\f[R], which handles both $PATH
@ -32,6 +32,8 @@ launcher.
While spmenu is based on dmenu, and is also fully compatible with dmenu,
spmenu introduces many new features which can be useful in shell
scripting.
.PP
It also serves as a dmenu replacement for Wayland users.
.SS Usage
.PP
On runtime, spmenu reads from standard input (stdin).
@ -76,12 +78,6 @@ Set max image cache size to size
\f[V]-cd, --cache-dir dir\f[R]
Set cache directory to dir
.TP
\f[V]-rw, --relative-width\f[R]
Enable relative input width
.TP
\f[V]-nrw, --no-relative-width\f[R]
Disable relative input width
.TP
\f[V]-ix, --print-index\f[R]
Print index instead of actual text
.TP
@ -388,6 +384,12 @@ Load theme (\[ti]/.config/spmenu/theme.conf) on runtime
\f[V]-nltm, --no-load-theme\f[R]
Don\[cq]t load theme (\[ti]/.config/spmenu/theme.conf) on runtime
.TP
\f[V]-x11, --x11\f[R]
Run spmenu in X11 mode
.TP
\f[V]-wl, --wayland\f[R]
Run spmenu in Wayland mode
.TP
\f[V]-v, --version\f[R]
Print spmenu version to stdout
.TP
@ -1448,6 +1450,8 @@ T}
.TE
.SS .Xresources
.PP
\f[B]NOTE: Only applies for X11 users\f[R]
.PP
spmenu also has .Xresources (xrdb) support built in.
It reads the xrdb (.Xresources database) on runtime.
You may disable it by passing -nxrdb, or enable it by padding -xrdb.
@ -1535,6 +1539,42 @@ Print the spmenu version
.TP
\f[V]spmenu:license\f[R]
Print the spmenu license
.SS Wayland support
.PP
Note that Wayland support is still experimental, and some features do
not currently work under Wayland.
Some will never work under Wayland due to limitations.
These are:
.IP \[bu] 2
Image support
.RS 2
.IP \[bu] 2
Images simply will not be drawn on Wayland.
.IP \[bu] 2
Will eventually be solved by replacing imlib2 with cairo.
.RE
.IP \[bu] 2
\f[V]--x-position\f[R] and \f[V]--y-position\f[R] arguments
.RS 2
.IP \[bu] 2
These arguments do not work under Wayland, because the layer_shell
protocol doesn\[cq]t allow clients to be placed on a specific position.
.RE
.IP \[bu] 2
Embedding \f[V]-w\f[R] and window manager managed \f[V]-wm\f[R]
.RS 2
.IP \[bu] 2
These arguments do not make much sense on Wayland, and embedding is not
possible due to the original implementation using XEmbed.
If the embed argument is passed it will simply be ignored and the window
will be layered as normal.
.RE
.IP \[bu] 2
\f[V]--monitor\f[R] argument
.IP \[bu] 2
Window borders
.IP \[bu] 2
Pasting
.SS License
.PP
spmenu is licensed under the MIT license because that\[cq]s the original

112
spmenu.c
View file

@ -21,6 +21,8 @@
#include <strings.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
// set version
#ifndef VERSION
@ -69,6 +71,13 @@
#define USEXRESOURCES 1
#endif
// check if we should enable Wayland support
#ifndef WAYLAND
#define USEWAYLAND 0
#else
#define USEWAYLAND 1
#endif
// include fribidi used for right to left language support
#if USERTL
#include <fribidi.h>
@ -98,6 +107,7 @@ static int allowkeys; // whether or not to interpret a keypress as an insertion
#include "libs/schemes.h"
#include "libs/arg.h"
#include "libs/x11/inc.h" // include x11
#include "libs/wl/inc.h" // include wayland
#include "libs/sort.h"
#include "libs/history.h"
@ -185,8 +195,6 @@ static int depth;
static Visual *visual;
static Colormap cmap;
static Drw *drw;
static Clr **scheme;
static Clr textclrs[256];
// declare functions
static int is_selected(size_t index);
@ -196,7 +204,10 @@ static void insert(const char *str, ssize_t n);
static void cleanup(void);
static void navigatehistfile(int dir);
static void pastesel(void);
static void resizeclient(void);
static void get_width(void);
static void grabfocus(void);
static void handle(void);
static void appenditem(struct item *item, struct item **list, struct item **last);
static int max_textw(void);
static size_t nextrune(int inc);
@ -240,6 +251,7 @@ static char *fonts[] = { font };
// include x11 code
#include "libs/x11/inc.c"
#include "libs/wl/inc.c"
// include more functions
#include "libs/history.c"
@ -348,17 +360,17 @@ void cleanup(void) {
cleanupimage(); // function frees images
#endif
// free color scheme
for (i = 0; i < LENGTH(colors) + 1; i++)
free(scheme[i]);
// free high priority items
for (i = 0; i < hplength; ++i)
free(hpitems[i]);
// free drawing and close the display
drw_free(drw);
if (!protocol) {
cleanup_x11(dpy);
}
free(sel_index);
}
@ -418,42 +430,82 @@ size_t nextrune(int inc) {
}
void pastesel(void) {
if (!protocol) {
pastesel_x11();
}
}
void resizeclient(void) {
#if USEWAYLAND
if (protocol) {
resizeclient_wl(&state);
} else {
resizeclient_x11();
}
#else
resizeclient_x11();
#endif
}
void get_width(void) {
inputw = mw / 3;
}
void handle(void) {
if (!protocol) {
handle_x11();
if (!drw_font_create(drw, fonts, LENGTH(fonts))) {
die("no fonts could be loaded.");
}
loadhistory(); // read history entries
store_image_vars();
// fast (-f) means we grab keyboard before reading standard input
if (fast && !isatty(0)) {
grabkeyboard_x11();
readstdin();
} else {
readstdin();
grabkeyboard_x11();
}
set_mode();
init_appearance(); // init colorschemes by reading arrays
setupdisplay_x11(); // set up display and create window
eventloop_x11(); // function is a loop which checks X11 events and calls other functions accordingly
#if USEWAYLAND
} else {
loadhistory();
store_image_vars();
drw = drw_create_wl(protocol);
if (!drw_font_create(drw, fonts, LENGTH(fonts))) {
die("no fonts could be loaded.");
}
readstdin();
set_mode();
init_appearance();
handle_wl();
#endif
}
}
int main(int argc, char *argv[]) {
readargs(argc, argv); // start by reading arguments
// open x11 display and create drawable
handle_x11();
// load fonts
if (!drw_font_create(drw, fonts, LENGTH(fonts)))
die("no fonts could be loaded.");
// pledge limits what programs can do, so here we specify what spmenu should be allowed to do
#ifdef __OpenBSD__
if (pledge("stdio rpath wpath cpath", NULL) == -1)
die("pledge");
#endif
loadhistory(); // read history entries
// fast (-f) means we grab keyboard before reading standard input
if (fast && !isatty(0)) {
grabkeyboard();
readstdin();
} else {
readstdin();
grabkeyboard();
}
store_image_vars();
set_mode();
init_appearance(); // init colorschemes by reading arrays
setupdisplay(); // set up display and create window
eventloop(); // function is a loop which checks X11 events and calls other functions accordingly
handle();
return 1; // should be unreachable
}

View file

@ -169,9 +169,9 @@
<h1 class="title">spmenu man page</h1>
</header>
<h1 id="spmenu">spmenu</h1>
<p>spmenu is an X11 menu application which takes standard input, parses
it, and lets the user choose an option and sends the selected option to
standard output.</p>
<p>spmenu is an X11 and Wayland menu application which takes standard
input, parses it, lets the user choose an option and sends the selected
option to standard output.</p>
<p>In addition to this, it also serves as a run launcher through the
included shell script <code>spmenu_run</code>, which handles both $PATH
listing, .desktop entries and file listing. See spmenu_run(1) for more
@ -179,6 +179,7 @@ information related to using spmenu as a run launcher.</p>
<p>While spmenu is based on dmenu, and is also fully compatible with
dmenu, spmenu introduces many new features which can be useful in shell
scripting.</p>
<p>It also serves as a dmenu replacement for Wayland users.</p>
<h2 id="usage">Usage</h2>
<p>On runtime, spmenu reads from standard input (stdin). spmenu items
are separated by a newline (<code>\n</code>). When (by default) Enter is
@ -222,14 +223,6 @@ Set max image cache size to size
<dd>
Set cache directory to dir
</dd>
<dt><code>-rw, --relative-width</code></dt>
<dd>
Enable relative input width
</dd>
<dt><code>-nrw, --no-relative-width</code></dt>
<dd>
Disable relative input width
</dd>
<dt><code>-ix, --print-index</code></dt>
<dd>
Print index instead of actual text
@ -635,6 +628,14 @@ Load theme (~/.config/spmenu/theme.conf) on runtime
<dd>
Dont load theme (~/.config/spmenu/theme.conf) on runtime
</dd>
<dt><code>-x11, --x11</code></dt>
<dd>
Run spmenu in X11 mode
</dd>
<dt><code>-wl, --wayland</code></dt>
<dd>
Run spmenu in Wayland mode
</dd>
<dt><code>-v, --version</code></dt>
<dd>
Print spmenu version to stdout
@ -1472,6 +1473,7 @@ a <code>keybinds.h</code> using
</tbody>
</table>
<h2 id="xresources">.Xresources</h2>
<p><strong>NOTE: Only applies for X11 users</strong></p>
<p>spmenu also has .Xresources (xrdb) support built in. It reads the
xrdb (.Xresources database) on runtime. You may disable it by passing
-nxrdb, or enable it by padding -xrdb. You can also set this in the
@ -1543,6 +1545,33 @@ Print the spmenu version
Print the spmenu license
</dd>
</dl>
<h2 id="wayland-support">Wayland support</h2>
<p>Note that Wayland support is still experimental, and some features do
not currently work under Wayland. Some will never work under Wayland due
to limitations. These are:</p>
<ul>
<li>Image support
<ul>
<li>Images simply will not be drawn on Wayland.</li>
<li>Will eventually be solved by replacing imlib2 with cairo.</li>
</ul></li>
<li><code>--x-position</code> and <code>--y-position</code> arguments
<ul>
<li>These arguments do not work under Wayland, because the layer_shell
protocol doesnt allow clients to be placed on a specific position.</li>
</ul></li>
<li>Embedding <code>-w</code> and window manager managed
<code>-wm</code>
<ul>
<li>These arguments do not make much sense on Wayland, and embedding is
not possible due to the original implementation using XEmbed. If the
embed argument is passed it will simply be ignored and the window will
be layered as normal.</li>
</ul></li>
<li><code>--monitor</code> argument</li>
<li>Window borders</li>
<li>Pasting</li>
</ul>
<h2 id="license">License</h2>
<p>spmenu is licensed under the MIT license because thats the original
suckless license. See the included LICENSE file for more

View file

@ -14,7 +14,7 @@
. ftr VB CB
. ftr VBI CBI
.\}
.TH "spmenu_run" "1" "" "1.2.1" "$PATH/.desktop launcher and file manager"
.TH "spmenu_run" "1" "" "2.0" "$PATH/.desktop launcher and file manager"
.hy
.SH spmenu_run
.PP