spmenu/spmenu.c

774 lines
17 KiB
C
Raw Normal View History

2023-03-06 16:23:03 +01:00
/* spmenu - speedie's dmenu fork
*
* If you're looking for functions used to draw text, see 'libs/draw.c'
* If you're looking for wrapper functions used inside the draw functions, see 'libs/sl/draw.c'
* If you're looking for functions used to draw images, see 'libs/img.c'
* If you're looking for the .Xresources array, see 'libs/xresources.h'
*
* You don't need to edit spmenu.c if you aren't making big changes to the software.
*
* After making changes, run 'make clean install' to install and 'make' to attempt a compilation.
* `make man` will generate a man page from 'docs/docs.md', which is a Markdown document. Run this before commiting.
*
* See LICENSE file for copyright and license details.
*/
2023-01-20 23:17:30 +01:00
#include <ctype.h>
#include <locale.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
// check if we should enable right to left language support
#ifndef RTL
#define USERTL 0
2023-02-28 15:51:32 +01:00
#else
#define USERTL 1
#endif
// check if we should enable pango or use xft
#ifndef PANGO
#define USEPANGO 0
#else
#define USEPANGO 1
#endif
// check if we should enable image support
#ifndef IMAGE
2023-02-26 16:38:26 +01:00
#define USEIMAGE 0
#else
#define USEIMAGE 1
#endif
// check if we should enable multimonitor support using libXinerama
2023-02-28 15:51:32 +01:00
#ifdef XINERAMA
#define USEXINERAMA 1
#else
#define USEXINERAMA 0
#endif
// include fribidi used for right to left language support
2023-02-28 15:51:32 +01:00
#if USERTL
#include <fribidi.h>
#endif
// include libraries used for image support
#if USEIMAGE
#include <errno.h>
#include <pwd.h>
#include <Imlib2.h>
#include <openssl/md5.h>
// openssl is used to generate a checksum, used for caching
// TODO: remove this dependency by doing it some other way
#endif
// include xinerama used for multi monitor support
2023-02-28 15:51:32 +01:00
#if USEXINERAMA
#include <X11/extensions/Xinerama.h>
#endif
// include X11 headers
#include <X11/XKBlib.h>
2023-01-20 23:17:30 +01:00
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/Xft/Xft.h>
// include pango used for markup
#if USEPANGO
2023-01-20 23:17:30 +01:00
#include <pango/pango.h>
#endif
2023-01-20 23:17:30 +01:00
// include macros and other defines
#include "libs/define.c"
// various headers
2023-03-06 16:08:31 +01:00
#include "libs/sl/draw.h"
#include "libs/sl/main.h"
#include "libs/stream.h"
#include "libs/schemes.h"
#include "libs/arg.h"
2023-03-06 14:15:01 +01:00
#include "libs/mode.h"
2023-03-06 16:23:03 +01:00
#include "libs/xrdb.h"
2023-03-08 17:20:32 +01:00
#include "libs/key.h"
#include "libs/mouse.h"
2023-03-09 10:10:29 +01:00
#include "libs/sort.h"
2023-02-25 17:44:52 +01:00
// misc
#include "libs/key_struct.c"
// text
static char text[BUFSIZ] = "";
2023-01-20 23:17:30 +01:00
static char numbers[NUMBERSBUFSIZE] = "";
// high priority
2023-03-09 10:10:29 +01:00
static int hplength = 0;
2023-03-09 11:56:44 +01:00
static char **hpitems = NULL;
// embed
2023-01-20 23:17:30 +01:00
static char *embed;
// keybinds
static int numlockmask = 0;
// height of each item, menu width, menu height
2023-01-20 23:17:30 +01:00
static int bh, mw, mh;
static int reallines = 0;
2023-03-16 17:25:39 +01:00
static int dmx = 0; // put spmenu at this x offset
static int dmy = 0; // put spmenu at this y offset (measured from the bottom if menuposition is 0)
static unsigned int dmw = 0; // make spmenu this wide
static int inputw = 0;
static int promptw;
static int plw = 0;
2023-03-16 17:25:39 +01:00
static int passwd = 0;
static int lrpad; // sum of left and right padding
static int vp; // vertical padding for bar
static int sp; // side padding for bar
2023-01-20 23:17:30 +01:00
static size_t cursor;
static struct item *items = NULL, *backup_items;
static struct item *matches, *matchend;
static struct item *prev, *curr, *next, *sel;
2023-03-06 16:23:03 +01:00
static int screen;
// item struct
struct item {
char *text;
#if USEIMAGE
char *image;
#endif
char *ex;
struct item *left, *right;
int hp;
double distance;
};
// image globals
#if USEIMAGE
static int flip = 0;
static int rotation = 0;
static int needredraw = 1;
static int longestedge = 0;
static int imagew = 0;
static int imageh = 0;
static int imageg = 0;
#endif
2023-03-16 14:56:41 +01:00
// set an integer to 1 if we have rtl enabled, this saves a lot of lines and duplicate code
#if USERTL
static int isrtl = 1;
#else
static int isrtl = 0;
#endif
// X11 properties
2023-01-22 22:12:37 +01:00
static Atom clip, utf8, types, dock;
2023-01-20 23:17:30 +01:00
static Display *dpy;
static Window root, parentwin, win;
static XIC xic;
// colors
2023-03-16 17:25:39 +01:00
static int useargb = 0;
2023-01-20 23:17:30 +01:00
static Visual *visual;
static int depth;
static Colormap cmap;
static Drw *drw;
static Clr *scheme[SchemeLast];
static Clr textclrs[256];
2023-03-16 14:56:41 +01:00
// history
2023-01-20 23:17:30 +01:00
static char *histfile;
static char **history;
static size_t histsz, histpos;
2023-03-16 17:25:39 +01:00
// declare functions
2023-02-25 17:44:52 +01:00
static void drawmenu(void);
2023-03-16 11:58:38 +01:00
static void drawhighlights(struct item *item, int x, int y, int w);
static void calcoffsets(void);
2023-03-02 11:40:52 +01:00
static void recalculatenumbers(void);
2023-03-02 14:53:48 +01:00
static void usage(void);
static void insert(const char *str, ssize_t n);
static void cleanup(void);
static void navigatehistfile(int dir);
static void grabfocus(void);
static void pastesel(void);
2023-03-13 21:21:40 +01:00
static void appenditem(struct item *item, struct item **list, struct item **last);
2023-03-08 17:20:32 +01:00
static int max_textw(void);
2023-03-16 14:56:41 +01:00
static size_t nextrune(int inc);
2023-02-25 17:44:52 +01:00
2023-03-16 14:56:41 +01:00
// user configuration
#include "options.h"
#include "keybinds.h"
2023-03-06 16:23:03 +01:00
2023-03-16 14:56:41 +01:00
// xresources/color arrays
2023-03-06 16:23:03 +01:00
#include "libs/xresources.h"
#include "libs/colors.h"
2023-01-20 23:17:30 +01:00
static char *fonts[] = { font };
2023-03-16 14:56:41 +01:00
// matching
2023-01-20 23:17:30 +01:00
static char * cistrstr(const char *s, const char *sub);
static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp;
static char *(*fstrstr)(const char *, const char *) = cistrstr;
2023-03-13 21:21:40 +01:00
// include functions
#include "libs/img.h"
#include "libs/img.c"
#include "libs/rtl.h"
#include "libs/rtl.c"
#include "libs/event.h"
#include "libs/event.c"
2023-03-08 17:20:32 +01:00
#include "libs/key.c"
#include "libs/mouse.c"
2023-03-09 10:10:29 +01:00
#include "libs/sort.c"
2023-03-02 11:40:52 +01:00
#include "libs/draw.c"
#include "libs/schemes.c"
2023-03-02 14:53:48 +01:00
#include "libs/argv.h"
#include "libs/argv.c"
2023-03-08 17:20:32 +01:00
#include "libs/xrdb.c"
#include "libs/mode.c"
#include "libs/client.h"
#include "libs/client.c"
2023-03-13 22:45:04 +01:00
#include "libs/match.h"
#include "libs/match.c"
#include "libs/arg.c"
#include "libs/stream.c"
2023-02-25 17:44:52 +01:00
void
2023-01-20 23:17:30 +01:00
appenditem(struct item *item, struct item **list, struct item **last)
{
if (*last)
(*last)->right = item;
else
*list = item;
item->left = *last;
item->right = NULL;
*last = item;
}
void
2023-01-20 23:17:30 +01:00
recalculatenumbers(void)
{
unsigned int numer = 0, denom = 0;
struct item *item;
if (matchend) {
numer++;
for (item = matchend; item && item->left; item = item->left)
numer++;
}
for (item = items; item && item->text; item++)
denom++;
snprintf(numbers, NUMBERSBUFSIZE, "%d/%d", numer, denom);
}
void
2023-01-20 23:17:30 +01:00
calcoffsets(void)
{
int i, n;
if (lines > 0)
n = lines * columns * bh;
else {
int numberWidth = 0;
int modeWidth = 0;
int larrowWidth = 0;
int rarrowWidth = 0;
2023-03-02 18:25:28 +01:00
if (!hidematchcount) numberWidth = pango_numbers ? TEXTWM(numbers) : TEXTW(numbers);
if (!hidemode) modeWidth = pango_mode ? TEXTWM(modetext) : TEXTW(modetext);
if (!hidelarrow) larrowWidth = pango_leftarrow ? TEXTWM(leftarrow) : TEXTW(leftarrow);
if (!hiderarrow) rarrowWidth = pango_rightarrow ? TEXTWM(rightarrow) : TEXTW(rightarrow);
n = mw - (promptw + inputw + larrowWidth + rarrowWidth + modeWidth + numberWidth);
}
// calculate which items will begin the next page and previous page
2023-01-20 23:17:30 +01:00
for (i = 0, next = curr; next; next = next->right)
if ((i += (lines > 0) ? bh : MIN(TEXTWM(next->text), n)) > n)
break;
for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
if ((i += (lines > 0) ? bh : MIN(TEXTWM(prev->left->text), n)) > n)
break;
}
int
2023-01-20 23:17:30 +01:00
max_textw(void)
{
int len = 0;
for (struct item *item = items; item && item->text; item++)
len = MAX(TEXTW(item->text), len);
return len;
}
void
2023-01-20 23:17:30 +01:00
cleanup(void)
{
size_t i;
#if USEIMAGE
cleanupimage();
#endif
2023-03-02 11:46:44 +01:00
2023-01-20 23:17:30 +01:00
XUngrabKey(dpy, AnyKey, AnyModifier, root);
2023-03-09 11:56:44 +01:00
2023-01-20 23:17:30 +01:00
for (i = 0; i < SchemeLast; i++)
free(scheme[i]);
2023-03-09 11:56:44 +01:00
for (i = 0; i < hplength; ++i)
free(hpitems[i]);
2023-01-20 23:17:30 +01:00
drw_free(drw);
XSync(dpy, False);
XCloseDisplay(dpy);
}
char *
2023-01-20 23:17:30 +01:00
cistrstr(const char *h, const char *n)
{
size_t i;
if (!n[0])
return (char *)h;
for (; *h; ++h) {
for (i = 0; n[i] && tolower((unsigned char)n[i]) ==
tolower((unsigned char)h[i]); ++i)
;
if (n[i] == '\0')
return (char *)h;
}
return NULL;
}
void
2023-01-20 23:17:30 +01:00
grabfocus(void)
{
struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 };
Window focuswin;
int i, revertwin;
for (i = 0; i < 100; ++i) {
XGetInputFocus(dpy, &focuswin, &revertwin);
if (focuswin == win)
return;
if (managed) {
XTextProperty prop;
char *windowtitle = prompt != NULL ? prompt : "spmenu";
Xutf8TextListToTextProperty(dpy, &windowtitle, 1, XUTF8StringStyle, &prop);
XSetWMName(dpy, win, &prop);
XSetTextProperty(dpy, win, &prop, XInternAtom(dpy, "_NET_WM_NAME", False));
XFree(prop.value);
} else {
XSetInputFocus(dpy, win, RevertToParent, CurrentTime);
}
nanosleep(&ts, NULL);
}
die("cannot grab focus");
}
void
2023-01-20 23:17:30 +01:00
insert(const char *str, ssize_t n)
{
if (strlen(text) + n > sizeof text - 1)
return;
2023-03-16 14:56:41 +01:00
// move existing text out of the way, insert new text, and update cursor
2023-01-20 23:17:30 +01:00
memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0));
if (n > 0)
memcpy(&text[cursor], str, n);
cursor += n;
match();
}
size_t
2023-01-20 23:17:30 +01:00
nextrune(int inc)
{
ssize_t n;
2023-03-16 14:56:41 +01:00
// return location of next utf8 rune in the given direction (+1 or -1)
2023-01-20 23:17:30 +01:00
for (n = cursor + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc)
;
return n;
}
void
2023-01-20 23:17:30 +01:00
loadhistory(void)
{
FILE *fp = NULL;
static size_t cap = 0;
size_t llen;
char *line;
if (!histfile) {
return;
}
fp = fopen(histfile, "r");
if (!fp) {
return;
}
for (;;) {
line = NULL;
llen = 0;
if (-1 == getline(&line, &llen, fp)) {
if (ferror(fp)) {
die("failed to read history");
}
free(line);
break;
}
if (cap == histsz) {
cap += 64 * sizeof(char*);
history = realloc(history, cap);
if (!history) {
die("failed to realloc memory");
}
}
strtok(line, "\n");
history[histsz] = line;
histsz++;
}
histpos = histsz;
if (fclose(fp)) {
die("failed to close file %s", histfile);
}
}
void
navigatehistfile(int dir)
2023-01-20 23:17:30 +01:00
{
static char def[BUFSIZ];
char *p = NULL;
size_t len = 0;
if (!history || histpos + 1 == 0)
return;
if (histsz == histpos) {
strncpy(def, text, sizeof(def));
}
switch (dir) {
case 1:
if (histpos < histsz - 1) {
p = history[++histpos];
} else if (histpos == histsz - 1) {
p = def;
histpos++;
}
break;
case -1:
if (histpos > 0) {
p = history[--histpos];
}
break;
2023-01-20 23:17:30 +01:00
}
2023-01-20 23:17:30 +01:00
if (p == NULL) {
return;
}
len = MIN(strlen(p), BUFSIZ - 1);
2023-03-06 21:19:12 +01:00
strcpy(text, p);
2023-01-20 23:17:30 +01:00
text[len] = '\0';
cursor = len;
match();
}
void
pastesel(void)
2023-01-20 23:17:30 +01:00
{
char *p, *q;
int di;
unsigned long dl;
Atom da;
2023-03-16 14:56:41 +01:00
// we have been given the current selection, now insert it into input
2023-01-20 23:17:30 +01:00
if (XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False,
utf8, &da, &di, &dl, &dl, (unsigned char **)&p)
== Success && p) {
insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p));
XFree(p);
}
drawmenu();
}
void
2023-01-20 23:17:30 +01:00
xinitvisual()
{
XVisualInfo *infos;
XRenderPictFormat *fmt;
int nitems;
int i;
2023-03-16 14:56:41 +01:00
// properties
2023-01-20 23:17:30 +01:00
XVisualInfo tpl = {
.screen = screen,
.depth = 32,
.class = TrueColor
};
2023-03-16 14:56:41 +01:00
2023-01-20 23:17:30 +01:00
long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
infos = XGetVisualInfo(dpy, masks, &tpl, &nitems);
visual = NULL;
for(i = 0; i < nitems; i ++) {
fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
visual = infos[i].visual;
depth = infos[i].depth;
cmap = XCreateColormap(dpy, root, visual, AllocNone);
useargb = 1;
break;
}
}
XFree(infos);
2023-03-16 14:56:41 +01:00
// no alpha, reset to default
2023-01-20 23:17:30 +01:00
if (!visual || !alpha) {
visual = DefaultVisual(dpy, screen);
depth = DefaultDepth(dpy, screen);
cmap = DefaultColormap(dpy, screen);
}
}
void
2023-01-20 23:17:30 +01:00
setup(void)
{
int x, y, i;
#if USEXINERAMA
int j, di;
#endif
2023-01-20 23:17:30 +01:00
unsigned int du;
2023-01-22 22:12:37 +01:00
unsigned int tmp, minstrlen = 0, curstrlen = 0;
int numwidthchecks = 100;
struct item *item;
2023-01-20 23:17:30 +01:00
XIM xim;
Window w, dw, *dws;
2023-03-08 17:20:32 +01:00
XWindowAttributes wa;
2023-02-28 15:51:32 +01:00
#if USEXINERAMA
2023-01-20 23:17:30 +01:00
XineramaScreenInfo *info;
Window pw;
2023-03-08 17:20:32 +01:00
int a, n, area = 0;
#endif
2023-01-20 23:17:30 +01:00
2023-03-16 14:56:41 +01:00
init_appearance(); // init colorschemes by reading arrays
2023-01-20 23:17:30 +01:00
2023-03-16 14:56:41 +01:00
// properties
2023-01-20 23:17:30 +01:00
clip = XInternAtom(dpy, "CLIPBOARD", False);
utf8 = XInternAtom(dpy, "UTF8_STRING", False);
2023-01-22 22:12:37 +01:00
types = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
dock = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
2023-01-20 23:17:30 +01:00
2023-03-13 22:45:04 +01:00
// resize client
2023-03-16 14:56:41 +01:00
bh = MAX(drw->font->h, drw->font->h + 2 + lineheight);
2023-01-20 23:17:30 +01:00
lines = MAX(lines, 0);
reallines = lines;
// resize client to image height if deemed necessary
#if USEIMAGE
if (image) resizetoimageheight(imageheight);
#endif
mh = (lines + 1) * bh; // lines + 1 * bh is the menu height
promptw = (prompt && *prompt)
? pango_prompt ? TEXTWM(prompt) : TEXTW(prompt) - lrpad / 4 : 0; // prompt width
2023-01-22 22:12:37 +01:00
// get accurate width
2023-01-22 22:12:37 +01:00
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;
}
}
}
}
2023-03-08 17:20:32 +01:00
// init xinerama screens
2023-02-28 15:51:32 +01:00
#if USEXINERAMA
2023-01-20 23:17:30 +01:00
i = 0;
if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
XGetInputFocus(dpy, &w, &di);
if (mon >= 0 && mon < n)
i = mon;
else if (w != root && w != PointerRoot && w != None) {
// find top-level window containing current input focus
2023-01-20 23:17:30 +01:00
do {
if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws)
XFree(dws);
} while (w != root && w != pw);
// find xinerama screen with which the window intersects most
2023-01-20 23:17:30 +01:00
if (XGetWindowAttributes(dpy, pw, &wa))
for (j = 0; j < n; j++)
if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) {
area = a;
i = j;
}
}
// no focused window is on screen, so use pointer location instead
2023-01-20 23:17:30 +01:00
if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du))
for (i = 0; i < n; i++)
if (INTERSECT(x, y, 1, 1, info[i]))
break;
// calculate x/y position
if (menuposition == 2) {
mw = MIN(MAX(max_textw() + promptw, minwidth), info[i].width);
2023-01-20 23:17:30 +01:00
x = info[i].x_org + ((info[i].width - mw) / 2);
y = info[i].y_org + ((info[i].height - mh) / 2);
} else {
x = info[i].x_org + dmx;
y = info[i].y_org + (menuposition ? 0 : info[i].height - mh - dmy);
mw = (dmw>0 ? dmw : info[i].width);
}
XFree(info);
} else
#endif
2023-01-20 23:17:30 +01:00
{
if (!XGetWindowAttributes(dpy, parentwin, &wa))
die("could not get embedding window attributes: 0x%lx",
parentwin);
if (menuposition == 2) {
2023-01-20 23:17:30 +01:00
mw = MIN(MAX(max_textw() + promptw, minwidth), wa.width);
x = (wa.width - mw) / 2;
y = (wa.height - mh) / 2;
} else {
x = 0;
y = 0;
mw = wa.width;
}
}
2023-01-22 22:12:37 +01:00
// might be faster in some instances, most of the time unnecessary
2023-01-22 22:12:37 +01:00
if (!accuratewidth) inputw = MIN(inputw, mw/3);
2023-02-25 03:46:26 +01:00
2023-01-20 23:17:30 +01:00
match();
// create menu window
create_window(x + sp, y + vp - (menuposition == 2 ? 0 : borderwidth * 2), mw - 2 * sp - borderwidth * 2, mh);
set_window();
set_prop();
2023-01-20 23:17:30 +01:00
2023-02-25 03:46:26 +01:00
#if USEIMAGE
setimageopts();
2023-02-25 03:46:26 +01:00
#endif
2023-01-20 23:17:30 +01:00
2023-03-16 17:25:39 +01:00
// input methods
2023-01-20 23:17:30 +01:00
if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL)
die("XOpenIM failed: could not open input device");
xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, win, XNFocusWindow, win, NULL);
XMapRaised(dpy, win);
if (embed) {
XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask);
if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) {
for (i = 0; i < du && dws[i] != win; ++i)
XSelectInput(dpy, dws[i], FocusChangeMask);
XFree(dws);
}
grabfocus();
}
// resize and draw
2023-01-20 23:17:30 +01:00
drw_resize(drw, mw, mh);
drawmenu();
}
int
main(int argc, char *argv[])
{
XWindowAttributes wa;
2023-03-02 14:53:48 +01:00
readargs(argc, argv);
2023-01-20 23:17:30 +01:00
#if USEIMAGE
longestedge = MAX(imagewidth, imageheight);
#endif
if (mode) {
2023-03-06 14:15:01 +01:00
curMode = 1;
2023-02-26 06:05:27 +01:00
allowkeys = 1;
strcpy(modetext, instext);
} else {
2023-03-06 14:15:01 +01:00
curMode = 0;
allowkeys = !curMode;
strcpy(modetext, normtext);
}
2023-01-20 23:17:30 +01:00
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
fputs("warning: no locale support\n", stderr);
2023-03-08 17:20:32 +01:00
if (!(dpy = XOpenDisplay(NULL)))
die("spmenu: cannot open display");
screen = DefaultScreen(dpy);
2023-01-20 23:17:30 +01:00
root = RootWindow(dpy, screen);
2023-03-08 17:20:32 +01:00
if (!embed || !(parentwin = strtol(embed, NULL, 0)))
2023-01-20 23:17:30 +01:00
parentwin = root;
2023-03-08 17:20:32 +01:00
if (!XGetWindowAttributes(dpy, parentwin, &wa))
die("spmenu: could not get embedding window attributes: 0x%lx", parentwin);
2023-01-20 23:17:30 +01:00
xinitvisual();
drw = drw_create(dpy, screen, root, wa.width, wa.height, visual, depth, cmap);
2023-03-20 15:32:20 +01:00
// load fonts
if (!drw_font_create(drw, fonts, LENGTH(fonts)))
2023-01-20 23:17:30 +01:00
die("no fonts could be loaded.");
2023-03-20 15:32:20 +01:00
lrpad = drw->font->h;
2023-03-08 17:20:32 +01:00
prepare_window_size();
2023-01-20 23:17:30 +01:00
2023-03-08 17:20:32 +01:00
#ifdef __OpenBSD__
2023-01-20 23:17:30 +01:00
if (pledge("stdio rpath", NULL) == -1)
die("pledge");
2023-03-08 17:20:32 +01:00
#endif
2023-01-20 23:17:30 +01:00
loadhistory();
2023-03-20 15:32:20 +01:00
// fast (-f) means we grab keyboard before reading standard input
2023-01-20 23:17:30 +01:00
if (fast && !isatty(0)) {
grabkeyboard();
readstdin();
} else {
readstdin();
grabkeyboard();
}
// set default values
#if USEIMAGE
if (!imagew || !imageh || !imageg) {
imagew = imagewidth;
imageh = imageheight;
imagegaps = imagegaps;
}
#endif
2023-01-20 23:17:30 +01:00
setup();
eventloop();
2023-01-20 23:17:30 +01:00
return 1;
2023-01-20 23:17:30 +01:00
}