This commit is contained in:
2020-12-04 05:19:07 +00:00
commit 77e564b9de
14 changed files with 1849 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT/X Consortium License
© 2020 phillbush
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

29
Makefile Normal file
View File

@ -0,0 +1,29 @@
include config.mk
SRCS = ${PROG}.c
OBJS = ${SRCS:.c=.o}
all: ${PROG}
${PROG}: ${OBJS}
${CC} -o $@ ${OBJS} ${LDFLAGS}
${OBJS}: config.h ${PROG}.h
.c.o:
${CC} ${CFLAGS} -c $<
clean:
-rm ${OBJS} ${PROG}
install: all
mkdir -p ${DESTDIR}${PREFIX}/bin
install -m 755 ${PROG} ${DESTDIR}${PREFIX}/bin/${PROG}
mkdir -p ${DESTDIR}${MANPREFIX}/man1
install -m 644 ${PROG}.1 ${DESTDIR}${MANPREFIX}/man1/${PROG}.1
uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/${PROG}
rm -f ${DESTDIR}${MANPREFIX}/man1/${PROG}.1
.PHONY: all clean install uninstall

77
README.md Normal file
View File

@ -0,0 +1,77 @@
<p align="center">
<img src="/demo.gif", title="demo"/>
</p>
# XMenu
XMenu is a menu utility for X.
XMenu receives a menu specification in stdin, shows a menu for the user
to select one of the options, and outputs the option selected to stdout.
XMenu can be controlled both via mouse and via keyboard.
In order to generate a menu of applications based on .desktop entries,
as specified by XDG, checkout [xdg-xmenu](https://github.com/OliverLew/xdg-xmenu)
by [OliverLew](https://github.com/OliverLew).
Check out my other project, [xclickroot](https://github.com/phillbush/xclickroot) for an application that can
spawn xmenu by right clicking on the root window (i.e. on the desktop).
## Features
XMenu comes with the following features:
* XMenu reads something in and prints something out, the UNIX way.
* Submenus (some menu entries can spawn another menu).
* Separators (menu entries can be separated by a line).
* Icons (menu entries can be preceded by an icon image).
* X resources support (you don't need to recompile xmenu for configuring it).
## Files
The files are:
* `./README`: This file.
* `./Makefile`: The makefile.
* `./config.h`: The hardcoded default configuration for XMenu.
* `./config.mk`: The setup for the makefile.
* `./demo.gif`: A gif demonstrating how XMenu works.
* `./xmenu.1`: The manual file (man page) for XMenu.
* `./xmenu.c`: The source code of XMenu.
* `./xmenu.sh`: A sample script illustrating how to use XMenu.
* `./icons/`: Icons for the sample script
## Installation
First, edit `./config.mk` to match your local setup.
In order to build XMenu you need the `Imlib2`, `Xlib` and `Xft` header files.
The default configuration for XMenu is specified in the file `config.h`,
you can edit it, but most configuration can be changed at runtime via
X resources. Enter the following command to build XMenu. This command
creates the binary file `./xmenu`.
make
By default, XMenu is installed into the `/usr/local` prefix. Enter the
following command to install XMenu (if necessary as root). This command
installs the binary file `./xmenu` into the `${PREFIX}/bin/` directory, and
the manual file `./xmenu.1` into `${MANPREFIX}/man1/` directory.
make install
## Running XMenu
XMenu receives as input a menu specification where each line is a menu
entry. Each line can be indented with tabs to represent nested menus.
Each line is made out of a label and a command separated by any number
of tabs. Lines without labels are menu separators.
See the script `./xmenu.sh` for an example of how to use XMenu to draw a
simple menu with submenus and separators. The file `./demo.gif` shows how
the menu generated by that script looks like.
Read the [manual](https://github.com/phillbush/xmenu/wiki) for more information on running XMenu.

57
config.h Normal file
View File

@ -0,0 +1,57 @@
Static ; struct Config config = {
/* font, separate different fonts with comma */
.font ="FiraCode Nerd Font:style=Light:size=8:antialias=true:autohint=true","Chiron Sans HK Light:style=Light:size=8","Noto Color Emoji:style=Regular",
/* colors */
.background_color = "#282a36",
.foreground_color = "#f8f8f2",
.selbackground_color = "#ff5555",
.selforeground_color = "#282a36",
.separator_color = "#bbbbbb",
.border_color = "#bbbbbb",
/* sizes in pixels */
.width_pixels = 15, /* minimum width of a menu */
.height_pixels = 25, /* height of a single menu item */
.border_pixels = 1, /* menu border */
.separator_pixels = 3, /* space around separator */
.gap_pixels = 5, /* gap between menus */
/*
* The variables below cannot be set by X resources.
* Their values must be less than .height_pixels.
*/
/* geometry of the right-pointing isoceles triangle for submenus */
.triangle_width = 3,
.triangle_height = 7,
/* the icon size is equal to .height_pixels - .iconpadding * 2 */
.iconpadding = 2,
/* area around the icon, the triangle and the separator */
.horzpadding = 8,
};
/*
* KEYBINDINGS
*
* Look at your /usr/include/X11/keysymdef.h (or the equivalent file
* in your system) for a list of key symbol constants, and change the
* macros below accordingly. All key symbol constants begin with the
* prefix XK_.
*
* For example, to use vim-like key bindings, set KEYSYMLEFT to XK_h,
* KEYSYMDOWN to XK_j, KEYSYMUP to XK_k, etc.
*
* Note that the regular keys like ArrowUp, ArrowDown, Tab, Home, etc
* will ALWAYS work, so you do not need to set them.
*
* If you do not want to set a key binding, keep it with the value of
* XK_VoidSymbol
*/
#define KSYMFIRST XK_VoidSymbol /* select first item */
#define KSYMLAST XK_VoidSymbol /* select last item */
#define KSYMUP XK_VoidSymbol /* select previous item */
#define KSYMDOWN XK_VoidSymbol /* select next item */
#define KSYMLEFT XK_VoidSymbol /* close current menu */
#define KSYMRIGHT XK_VoidSymbol /* enter selected item */

28
config.mk Normal file
View File

@ -0,0 +1,28 @@
# program name
PROG = xmenu
# paths
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man
LOCALINC = /usr/local/include
LOCALLIB = /usr/local/lib
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
FREETYPEINC = /usr/include/freetype2
# OpenBSD (uncomment)
#FREETYPEINC = ${X11INC}/freetype2
# includes and libs
INCS = -I${LOCALINC} -I${X11INC} -I${FREETYPEINC}
LIBS = -L${LOCALLIB} -L${X11LIB} -lfontconfig -lXft -lX11 -lXinerama -lImlib2
# flags
CPPFLAGS =
CFLAGS = -Wall -Wextra ${INCS} ${CPPFLAGS}
LDFLAGS = ${LIBS}
# compiler and linker
CC = cc

BIN
demo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
icons/gimp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
icons/web.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
xmenu Executable file

Binary file not shown.

200
xmenu.1 Normal file
View File

@ -0,0 +1,200 @@
.TH XMENU 1
.SH NAME
xmenu \- menu utility for X
.SH SYNOPSIS
.B xmenu
.RB [ \-irw ]
.RB [ -p
.IR position ]
.RI [ title ]
.SH DESCRIPTION
.B xmenu
is a menu for X,
it reads a list of newline-separated items from stdin,
shows a menu for the user to select one of the items,
and outputs the item selected to stdout.
.PP
The options are as follows:
.TP
.B -i
Disable icons.
This makes xmenu loading faster when not using icons.
.TP
.BI -p " position"
Set the position to spawn xmenu.
Without this option, xmenu spawns next to the cursor.
.I position
is a string of the form
.BR INTxINT[:MONITOR] ,
where the first INT is the x position and the second INT is the y position.
The monitor part between brackets is optional.
.B MONITOR
can be a number from 0 to the number of monitors minus 1;
or it can be a string like
.B current
or
.BR cursor .
If present, the monitor specifies that the position is relative to the upper left corner
of that monitor.
If
.B monitor
is
.B current
or
.BR cursor ,
the monitor to be used is that where the cursor is in.
For example,
.B -p 0x0:cursor
specifies that
.B xmenu
must spawn at the position 0x0 of the monitor where the cursor is in.
And
.B -p 100x500:0
specifies that
.B xmenu
must spawn at the position 100x500 of the monitor 0.
.TP
.B -r
If this option is set, the right mouse button is disabled;
so pressing it will not trigger any menu item.
.TP
.B -w
Asks the window manager to draw a border around the menus.
This option may be buggy in some window managers,
specially tiled ones that do not respect window hints.
.PP
Each item read from stdin has the following format:
.IP
.EX
ITEM := [TABS] [[IMAGE TABS] LABEL [TABS OUTPUT]] NEWLINE
.EE
.PP
That means that each item is composed by
tabs, followed by an optional image specification, followed by tabs
followed by a label, followed by more tabs, followed by an output,
and ended by a newline. Brackets group optional elements.
.IP
The initial tabs indicate the menu hierarchy:
items indented with a tab is shown in a submenu of the preceding item not indented.
An item without initial tabs is a top-level item.
.IP
The image is a string of the form "IMG:/path/to/image.png".
It specifies a image to be shown as icon at the left of the entry.
.IP
The label is the string that will be shown as a item in the menu.
An item without label is considered a separator and is drawn as a thin line in the menu
separating the item above from the item below.
.IP
The output is the string that will be output after selecting the item.
If an item does not have an output, its label is used as its output.
.IP
The newline terminates the item specification.
.PP
If the argument
.I title
is given, the title of the menu window is set to it.
.SH USAGE
.B xmenu
is controlled by the mouse,
but can also be controlled by the keyboard.
Items can be selected using the arrow keys,
Tab (with and without Shift),
Home, End,
Enter and Esc, and 1-9 keys.
.TP
.BR Home
Select the first item in the menu.
.TP
.BR End
Select the last item in the menu.
.TP
.BR Down ", " Tab
Cycle through the items in the regular direction.
.TP
.BR Up ", " Shift-Tab
Cycle through the items in the reverse direction.
.TP
.BR Right ", " Enter
Select the highlighted item.
.TP
.B Left
Go to the menu above.
.TP
.B Esc
Go to the menu above or exit xmenu.
.PP
Additional key bindings can be set at compile time by changing the
.B config.h
file.
.SH RESOURCES
.B
xmenu
understands the following X resources.
.TP
.B xmenu.font
The font in which the labels should be drawn.
Multiple fonts can be added as fallback fonts;
they must be separated by a comma.
.TP
.B xmenu.background
The background color of non-selected items in the menu.
.TP
.B xmenu.foreground
The color of the label text of non-selected items in the menu.
.TP
.B xmenu.selbackground
The background color of selected items in the menu.
.TP
.B xmenu.selforeground
The color of the label text of selected items in the menu.
.TP
.B xmenu.border
The color of the border around the menu.
.TP
.B xmenu.separator
The color of the separator between items in the menu.
.TP
.B xmenu.gap
The gap, in pixels, between the menus.
.TP
.B xmenu.width
The minimum width, in pixels, of the items in the menu.
.TP
.B xmenu.height
The size in pixels of the height of a single menu item.
.TP
.B xmenu.borderWidth
The size in pixels of the border around the menu.
.TP
.B xmenu.separatorWidth
The size in pixels of the item separator.
.SH EXAMPLES
The following script illustrates the use of
.BR xmenu .
The output is redirected to
.IR sh (1),
creating a command to be run by the shell.
.IP
.EX
#!/bin/sh
cat <<EOF | xmenu | sh &
Applications
IMG:./web.png Web Browser firefox
IMG:./gimp.png Image editor gimp
Terminal (xterm) xterm
Terminal (urxvt) urxvt
Terminal (st) st
Shutdown poweroff
Reboot reboot
EOF
.EE
.PP
For example, by selecting \(lqApplications\(rq, a new menu will appear.
Selecting \(lqWeb Browser\(rq in the new menu opens firefox.
.SH SEE ALSO
.IR dmenu (1),
.IR 9menu (1),
.IR thingmenu (1)

1334
xmenu.c Normal file

File diff suppressed because it is too large Load Diff

90
xmenu.h Normal file
View File

@ -0,0 +1,90 @@
#define PROGNAME "xmenu"
/* enum for keyboard menu navigation */
enum { ITEMPREV, ITEMNEXT, ITEMFIRST, ITEMLAST };
/* macros */
#define LEN(x) (sizeof (x) / sizeof (x[0]))
#define MAX(x,y) ((x)>(y)?(x):(y))
#define MIN(x,y) ((x)<(y)?(x):(y))
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
/* color enum */
enum {ColorFG, ColorBG, ColorLast};
/* EWMH atoms */
enum {NetWMName, NetWMWindowType, NetWMWindowTypePopupMenu, NetLast};
/* configuration structure */
struct Config {
/* the values below are set by config.h */
const char *font;
const char *background_color;
const char *foreground_color;
const char *selbackground_color;
const char *selforeground_color;
const char *separator_color;
const char *border_color;
int width_pixels;
int height_pixels;
int border_pixels;
int separator_pixels;
int gap_pixels;
int triangle_width;
int triangle_height;
int iconpadding;
int horzpadding;
/* the values below are set by options */
int monitor;
int posx, posy; /* rootmenu position */
/* the value below is computed by xmenu */
int iconsize;
};
/* draw context structure */
struct DC {
XftColor normal[ColorLast];
XftColor selected[ColorLast];
XftColor border;
XftColor separator;
GC gc;
FcPattern *pattern;
XftFont **fonts;
size_t nfonts;
};
/* menu item structure */
struct Item {
char *label; /* string to be drawed on menu */
char *output; /* string to be outputed when item is clicked */
char *file; /* filename of the icon */
int y; /* item y position relative to menu */
int h; /* item height */
struct Item *prev; /* previous item */
struct Item *next; /* next item */
struct Menu *submenu; /* submenu spawned by clicking on item */
Drawable sel, unsel; /* pixmap for selected and unselected item */
Imlib_Image icon;
};
/* monitor geometry structure */
struct Monitor {
int x, y, w, h; /* monitor geometry */
};
/* menu structure */
struct Menu {
struct Menu *parent; /* parent menu */
struct Item *caller; /* item that spawned the menu */
struct Item *list; /* list of items contained by the menu */
struct Item *selected; /* item currently selected in the menu */
int x, y, w, h; /* menu geometry */
int hasicon; /* whether the menu has item with icons */
int drawn; /* whether the menu was already drawn */
unsigned level; /* menu level relative to root */
Window win; /* menu window to map on the screen */
};

BIN
xmenu.o Normal file

Binary file not shown.

13
xmenu.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/sh
cat <<EOF | xmenu | sh &
Applications
IMG:./icons/web.png Web Browser firefox
IMG:./icons/gimp.png Image editor gimp
Terminal (xterm) xterm
Terminal (urxvt) urxvt
Terminal (st) st
Shutdown poweroff
Reboot reboot
EOF